home *** CD-ROM | disk | FTP | other *** search
Text File | 2000-06-23 | 96.8 KB | 3,399 lines |
- // =================================================================================
- // ProxyModule.c ©1996-1999 Sustainable Softworks All rights reserved.
- // =================================================================================
- // DLPI STREAMS filter and TPI STREAMS Driver
- //
- // This module is both a STREAMS module "Proxym" and STREAMS driver "Proxy".
- //
- // The module is autopushed above a DLPI device (such as PPP) to monitor
- // network traffic flowing to that device.
- //
- // The module is opened as a driver to communicate monitored statistics
- // to a network client above the stream head.
- //
- // Currently, we just count data bytes flowing in each direction.
- //
- // Original Version 8/2/96 by Peter Sichel
-
- #if powerc
- #include "DCon.h"
- #endif
- #ifndef __OPENTPTMODULE__
- #include <OpenTptModule.h>
- #endif
- #ifndef _MPS_STROPTS_
- #include <stropts.h>
- #endif
- #ifndef _TIHDR_
- #include <tihdr.h>
- #endif
- #ifndef __DLPI__
- #include <dlpi.h>
- #endif
- #include <OpenTptLinks.h>
-
- #include <OpenTptInternet.h>
- #include "ProxyModule.h"
- #include "NatProcess.h"
- #include "FilterTable.h"
-
- #define nilp(type) ((type*)0)
-
- //--------------------------------------------------------------
- // • Forward function declarations
- //--------------------------------------------------------------
- int proxy_admin(void);
- int proxy_close(queue_t*, int, cred_t*);
- int proxy_open(queue_t*, dev_t*, int, int, cred_t*);
- int proxy_rsrv(queue_t*);
- int proxy_wsrv(queue_t*);
- int proxy_rput(queue_t*, mblk_t*);
- int proxy_wput(queue_t*, mblk_t*);
-
- int proxy_wproto(queue_t* wrq, mblk_t*);
- int proxy_wdata(queue_t* wrq, mblk_t*);
- int proxy_rproto(queue_t* rdq, mblk_t*);
- int proxy_rdata(queue_t* rdq, mblk_t*);
-
- int proxym_close(queue_t*, int, cred_t*);
- int proxym_open(queue_t*, dev_t*, int, int, cred_t*);
- int proxym_rsrv(queue_t*);
- int proxym_wsrv(queue_t*);
- int proxym_rput(queue_t*, mblk_t*);
- int proxym_wput(queue_t*, mblk_t*);
-
- int proxym_wproto(queue_t* wrq, mblk_t*);
- int proxym_wdata(queue_t* wrq, mblk_t*);
- int proxym_rproto(queue_t* rdq, mblk_t*);
- int proxym_rdata(queue_t* rdq, mblk_t*);
-
- int proxy_error(queue_t* rdq, mblk_t*, int error);
- void ReplyErrorAck(queue_t* rdq, mblk_t*, long reqType,
- int xtiErr, int macErr);
- mblk_t* ReuseMessage(mblk_t* mp, size_t size);
- SInt32 proxy_CountMessage(mblk_t* mp);
- UInt32 HashName(char* inName);
- void proxy_GetTimedStat(queue_t* q, SInt32* outSequenceNumber, SInt32* outRCount, SInt32* outWCount);
- Boolean proxy_SendStats(queue_t* q);
- Boolean proxy_SendNat(translationEntry_t table[], queue_t* q, UInt8 selector);
- Boolean proxy_SendFilters(queue_t* q);
-
- mblk_t* my_tpi_unitdata_ind(mblk_t* trailer_mp, char* src, size_t src_length,
- char* opt, size_t opt_length);
- UInt8* FindWDatagram(queue_t* q, mblk_t* mp, mblk_t** outMp, SInt32* dataOffset);
- UInt8* FindRDatagram(queue_t* q, mblk_t* mp, mblk_t** outMp, SInt32* dataOffset);
- UInt8 FilterPacket(UInt8* datagram, mblk_t* mp, FilterEntry_t* filterData);
-
- // ===========================================================================
-
- #pragma mark • Shared Global Data •
-
- //--------------------------------------------------------------
- // • Global Driver Variables
- //--------------------------------------------------------------
-
- static char* gProxymListHead = NULL; // used for mi_open and mi_close support code
- static char* gProxyListHead = NULL;
-
- // Statistics information
- struct proxy_stats
- {
- SInt32 flags;
- SInt32 rCount;
- SInt32 wCount;
- SInt32 filter1;
- SInt32 filter2;
- SInt32 filter3;
- SInt32 filter4;
- };
- static struct proxy_stats mstat =
- {
- 0, // flags
- 0, // read data count
- 0, // write data count
- 0, // filter1 value
- 0, // filter2 value
- 0, // filter3 value
- 0 // filter4 value
- };
-
- static Boolean proxymRefCountAdjusted = false;
- static Boolean proxyRefCountAdjusted = false;
- static Boolean gIsLocalNatOn; // Local NAT on/off
- static Boolean gIsTRCableModem; // Enable TRCableModem
- static Boolean gIsDNSForwarding; // Enable DNS Forwarding
- static Boolean gIsOnDemandUp;
- static Boolean gIsOnDemandPending; // On Demand connection needed
- static UInt32 gOnDemandName; // Hashed OnDemand interface selector
- static UInt32 gMonitorName; // Hashed Monitor interface selector
- static UInt32 gOnDemandSrcAddress;// src address of on demand traffic
- static UInt16 gFlakePercent; // 0-100
- static UInt16 gFlakeLatency; // ms
-
- // NAT table storage
- static translationEntry_t gNatTable0[kNatTableDim];
- static translationEntry_t gNatTable1[kNatTableDim];
- static translationEntry_t gNatTable2[kNatTableDim];
- static translationEntry_t gNatTable3[kNatTableDim];
-
- static translationEntry_t* gNatTable[kNatNumDim];
-
- // Filter table storage
- static FilterEntry_t gFilterTable[kFilterTableDim];
-
-
- //--------------------------------------------------------------
- // • Proxym STREAMS structures
- //--------------------------------------------------------------
-
- /*
- * Module information for the streamtab structure
- */
- static struct module_info proxym_minfo = // pushable DLPI streams module
- {
- 9002, /* Module Number */
- "Proxym", /* Name of module */
- 0, /* Minimum data size */
- INFPSZ, /* Maximum data size */
- 2048, /* Hi water mark for queue */
- 128 /* Lo water mark for queue */
- };
-
- /*
- * Info for the "read" queue.
- */
-
- static struct qinit proxym_rinit =
- {
- proxym_rput, /* Put routine for "incoming" data */
- proxym_rsrv, /* Service routine for "incoming" data */
- proxym_open, /* Our open routine */
- proxym_close, /* Our close routine */
- proxy_admin, /* Our admin routine */
- &proxym_minfo, /* Our module_info */
- };
-
- /*
- * Info for the "write" queue
- */
-
- static struct qinit proxym_winit =
- {
- proxym_wput, /* Put routine for client data */
- proxym_wsrv, /* Service routine for client data */
- 0, /* open routine goes in read-side structure */
- 0, /* close routine goes in read-side structure */
- 0, /* admin routine goes in read-side structure */
- &proxym_minfo /* Our module_info */
- };
-
- /*
- * The streamtab structure
- */
-
- static struct streamtab proxymStreamTab =
- {
- &proxym_rinit, /* Our read-side qinit structure */
- &proxym_winit, /* Our write-side qinit structure */
- 0, /* Not a mux - no structure info */
- 0 /* Not a mux - no structure info */
- };
-
- static struct install_info proxymInstallInfo =
- {
- &proxymStreamTab, // Stream Tab pointer
- kOTModIsModule + kOTModIsFilter, // Tell OT we're a filter module
- SQLVL_QUEUE, // Synchronization level
- 0, // Shared writer list buddy
- 0, // Open Transport use - always set to 0
- 0 // Flag - always set to 0
- };
-
- //--------------------------------------------------------------
- // • Proxy STREAMS structures
- //--------------------------------------------------------------
-
- /*
- * Module information for the streamtab structure
- */
- static struct module_info proxy_minfo = // TPI streams driver
- {
- 9003, /* Module Number */
- "Proxy", /* Name of module */
- 0, /* Minimum data size */
- INFPSZ, /* Maximum data size */
- 2048, /* Hi water mark for queue */
- 128 /* Lo water mark for queue */
- };
-
- /*
- * Info for the "read" queue.
- */
-
- static struct qinit proxy_rinit =
- {
- proxy_rput, /* Put routine for "incoming" data */
- proxy_rsrv, /* Service routine for "incoming" data */
- proxy_open, /* Our open routine */
- proxy_close, /* Our close routine */
- proxy_admin, /* Our admin routine */
- &proxy_minfo, /* Our module_info */
- };
-
- /*
- * Info for the "write" queue
- */
-
- static struct qinit proxy_winit =
- {
- proxy_wput, /* Put routine for client data */
- proxy_wsrv, /* Service routine for client data */
- 0, /* open routine goes in read-side structure */
- 0, /* close routine goes in read-side structure */
- 0, /* admin routine goes in read-side structure */
- &proxy_minfo /* Our module_info */
- };
-
- /*
- * The streamtab structure
- */
-
- static struct streamtab proxyStreamTab =
- {
- &proxy_rinit, /* Our read-side qinit structure */
- &proxy_winit, /* Our write-side qinit structure */
- 0, /* Not a mux - no structure info */
- 0 /* Not a mux - no structure info */
- };
-
- static struct install_info proxyInstallInfo =
- {
- &proxyStreamTab, // Stream Tab pointer
- kOTModIsDriver + kOTModUpperIsTPI + kOTModGlobalContext,
- SQLVL_MODULE, // Synchronization level - the module will never
- // be re-entered with this setting
- 0, // Shared writer list buddy
- 0, // Open Transport use - always set to 0
- 0 // Flag - always set to 0
- };
-
-
- // ===========================================================================
-
- #pragma mark -
- #pragma mark ••• Proxym STREAMS Module •••
- #pragma mark • module structure & procedures •
-
- /*******************************************************************************
- ** Open routine
- ********************************************************************************/
-
- typedef struct error_struct
- {
- long reqType;
- queue_t* rdq;
- int xtiErr;
- int macErr;
- Boolean allocd;
- } error_struct;
-
- typedef struct proxym_struct
- {
- int myError;
- UInt16 myState;
- UInt16 myProtocolType;
- UInt32 myInterfaceName;
- UInt32 myFastPathHeaderSize;
- UInt16 myPacketCount; // used for flakeway
- mblk_t* timerMessage;
- error_struct myErrorStruct;
- Boolean errInUse;
- } proxym_struct;
-
- int proxym_open(queue_t* rdq, dev_t* devp, int flag, int sflag, cred_t* credp)
- {
- int err;
- proxym_struct* myData;
- TPortRecord* thePortRecord;
-
- // adjust ref count so we don't unload until companion module is free
- if ( OTCompareAndSwap32(1, 2, &proxymInstallInfo.ref_count) )
- proxymRefCountAdjusted = true;
-
- err = mi_open_comm(&gProxymListHead, sizeof(proxym_struct),
- rdq, devp, flag, sflag, credp);
-
- if (err == 0) {
- // Set my state in my data structure
- myData = (proxym_struct*)rdq->q_ptr;
-
- myData->myState = DL_UNBOUND;
- myData->myProtocolType = 0;
- thePortRecord = OTFindPortByDev(*devp);
- myData->myInterfaceName = HashName(thePortRecord->fPortName);
- myData->myFastPathHeaderSize = 0;
- //OTKernelPrintf( kOTPrintOnly, "port name: %s.\n", thePortRecord->fPortName);
- myData->errInUse = false;
- myData->myErrorStruct.allocd = false;
- // flakeway
- myData->myPacketCount = 0;
- myData->timerMessage = nilp(mblk_t);
- }
- //dprintf("\nProxy module opened");
- // return result
- return err;
- }
-
- /*******************************************************************************
- ** Close routine
- ********************************************************************************/
-
- int proxym_close(queue_t* rdq, int flags, cred_t* credP)
- {
- int err;
- proxym_struct* myData = (proxym_struct*)rdq->q_ptr;
-
- //OTKernelPrintf( kOTPrintThenStop, "proxym_close, ref_count: %d, %d.\n",
- // proxymInstallInfo.ref_count, proxyInstallInfo.ref_count);
-
- // if timerMessage is pending, cancel it
- if (myData->timerMessage) {
- proxym_wsrv(WR(rdq)); // release any waiting messages
- // cancel timer
- mi_timer_free(myData->timerMessage);
- myData->timerMessage = nilp(mblk_t);
- }
-
- err = mi_close_comm(&gProxymListHead, rdq);
-
- // adjust ref count so we don't unload until companion module is free
- if (proxyInstallInfo.ref_count <= 1) { // if done with companion
- // if I'm done, and my ref_count was adjusted,
- // decrement my ref_count so it can go to zero and
- if (proxymRefCountAdjusted) {
- if ( OTCompareAndSwap32(2, 1, &proxymInstallInfo.ref_count) ) {
- proxyInstallInfo.ref_count = 0; // set companion to zero ???
- proxymRefCountAdjusted = false; // indicate no longer adjusted
- }
- }
- }
-
- // return result
- return err;
- }
-
- /*******************************************************************************
- ** Admin routine
- **
- ** Admin routines are for future expansion - just return no error.
- ********************************************************************************/
-
- int proxy_admin()
- {
- return kOTNoError;
- }
-
- /*******************************************************************************
- ** Write-side put routine
- ********************************************************************************/
-
- int proxym_wput(queue_t* q, mblk_t* mp)
- {
- //OTKernelPrintf( kOTPrintThenStop, "Entering proxy_wput, db_type: %d.\n", mp->b_datap->db_type);
- /*
- * Process the incoming message from the client
- */
- switch (mp->b_datap->db_type)
- {
-
- /*
- * Request to flush queues.
- */
- case M_FLUSH:
- // Do the job, then pass the message on
- if ( mp->b_rptr[0] & FLUSHW)
- {
- if ( (mp->b_rptr[0] & FLUSHBAND) && mp->b_wptr - mp->b_rptr == 2 )
- flushband(q, mp->b_rptr[1], FLUSHALL);
- else
- flushq(q, FLUSHALL);
- }
- if ( mp->b_rptr[0] & FLUSHR )
- {
- if ( (mp->b_rptr[0] & FLUSHBAND) && mp->b_wptr - mp->b_rptr == 2 )
- flushband(RD(q), mp->b_rptr[1], FLUSHALL);
- else
- flushq(RD(q), FLUSHALL);
- }
- break;
-
- /*
- * Handle data coming from the client
- */
- case M_DATA:
- return proxym_wdata(q, mp);
-
- /*
- * Handle M_PROTO and M_PCPROTO requests coming from the client
- */
- case M_PROTO:
- case M_PCPROTO:
- return proxym_wproto(q, mp);
-
- case M_IOCTL:
- {
- struct iocblk* iocp = (struct iocblk*)mp->b_rptr;
- //dprintf("\nwput IOCTL, ioc_cmd: %x", iocp->ioc_cmd);
- break;
- }
- default:
- break;
- }
- // just pass it on
- putnext(q, mp);
- return 0;
- }
-
- /*******************************************************************************
- ** Read-side put routine
- ********************************************************************************/
-
- int proxym_rput(queue_t* q, mblk_t* mp)
- {
- //OTKernelPrintf( kOTPrintThenStop, "Entering proxym_rput, db_type: %d.\n", mp->b_datap->db_type);
- proxym_struct* myData = (proxym_struct*)q->q_ptr;
- /*
- * Process the incoming message from the driver below us
- */
- switch (mp->b_datap->db_type)
- {
-
- /*
- * Request to flush queues. Do the job, then pass the message on
- */
- case M_FLUSH:
- if ( mp->b_rptr[0] & FLUSHW)
- {
- if ( (mp->b_rptr[0] & FLUSHBAND) && mp->b_wptr - mp->b_rptr == 2 )
- flushband(WR(q), mp->b_rptr[1], FLUSHALL);
- else
- flushq(WR(q), FLUSHALL);
- }
- if ( mp->b_rptr[0] & FLUSHR )
- {
- if ( (mp->b_rptr[0] & FLUSHBAND) && mp->b_wptr - mp->b_rptr == 2 )
- flushband(q, mp->b_rptr[1], FLUSHALL);
- else
- flushq(q, FLUSHALL);
- }
- break;
-
- /*
- * Handle data coming from downstream
- */
- case M_DATA:
- return proxym_rdata(q, mp);
-
- /*
- * Handle M_PROTO and M_PCPROTO requests coming from downstream
- */
- case M_PROTO:
- case M_PCPROTO:
- return proxym_rproto(q, mp);
-
- /*
- * If we send any IOCTLs downstream, look at the acks and
- * nacks here to determine if these are ours. If so, process
- * them. Otherwise, just send them on upstream
- */
- case M_IOCACK:
- {
- struct iocblk* iocp = (struct iocblk*)mp->b_rptr;
- proxym_struct* myData = (proxym_struct*)q->q_ptr;
- mblk_t* cp;
- //dl_unitdata_ind_t* up;
-
- if (iocp->ioc_cmd == DL_IOC_HDR_INFO) {
- // examine FastPath ACK to determine header size
- //dprintf("\nproxym_rput DL_IOC_HDR_INFO");
- // we expect to see a DL_UNITDATA_IND followed
- // by the actual FastPath header
- cp = mp->b_cont;
- if (cp == nil) break;
- //dprintf("\nproxym_rput found attached block type %d prim %0x", cp->b_datap->db_type, up->dl_primitive);
- //up = (dl_unitdata_ind_t*)cp->b_rptr;
- //if (up->dl_primitive > 0) { // observed 0 or 0xffc10000, Mentat says it's a template for DL_UNITDATA_IND
- if (true) {
- //dprintf("\nproxym_rput found %0x", up->dl_primitive);
- // get size of FastPath header
- cp = cp->b_cont;
- if (cp == nil) break;
- //dprintf("\nproxym_rput found attached block");
- myData->myFastPathHeaderSize = cp->b_wptr - cp->b_rptr;
- //dprintf("\nproxym_rput FastPathHeaderSize: %d", myData->myFastPathHeaderSize);
- }
-
- }
- }
- break;
-
- case M_IOCNAK:
- break;
-
- case M_PCSIG:
- // record timer has been delivered, so we don't try to cancel it
- myData->timerMessage = nilp(mblk_t);
- // Test if message is valid
- if ( !mi_timer_valid(mp) ) return 0; // If not valid, ignore it!
- mi_timer_free(mp); // free the message
- // release any waiting messages
- proxym_wsrv(WR(q));
- // done
- return 0;
- /*
- * Anything we don't understand - just pass it on
- */
- default:
- break;
- }
- putnext(q, mp);
- return 0;
- }
-
- #pragma mark • module support functions •
-
-
- /*******************************************************************************
- ** Write-side processing routines
- ********************************************************************************/
-
- int proxym_wdata(queue_t* q, mblk_t* mp)
- {
- proxym_struct* myData = (proxym_struct*)RD(q)->q_ptr;
- Boolean result = true;
- mblk_t* cp; // message block pointer
- UInt8* datagram; // datagram pointer
- FilterEntry_t filterData;
- SInt32 dataOffset;
- SInt32 dataCount;
- // UInt8 i;
- UInt8 filterAction;
- UInt8 flakeFactor;
- Boolean flakeAction; // false=drop, true=pass
- Boolean match;
- /* ---------------------------------------------------------------------
- Here, we do whatever munging we're going to do on the client data,
- then send it on.
- Keep in mind that we call this routine from the proxy_wproto routine,
- so that the first block of the message might be an M_PROTO, and not
- data.
- --------------------------------------------------------------------- */
-
- // Check for IP data if protocol is specified
- if ((myData->myProtocolType == kProtocolTypeNone) ||
- (myData->myProtocolType == kProtocolTypeIP)) {
-
- // find datagram and containing message block (put in cp)
- datagram = FindWDatagram(q, mp, &cp, &dataOffset);
-
- // count data for monitor display
- if ((myData->myInterfaceName == gMonitorName) || (gMonitorName == 0)) {
- dataCount = proxy_CountMessage(mp) - dataOffset;
- OTAtomicAdd32(dataCount, &mstat.wCount);
- //OTKernelPrintf( kOTPrintOnly, "proxy_wdata wCount is: %d.\n", mstat.wCount);
- }
-
-
- //
- // for outbound packets: filter first, then NAT
- //
- // Process IP filtering
- filterAction = kFilterNoDial;
- if (datagram != nil) {
- filterData.portName = myData->myInterfaceName;
- filterData.flags = 0; // kFlagDirectionRead = 0
- filterAction = FilterPacket(datagram, cp, &filterData);
- if (filterAction == kFilterReject) {
- // kill it
- freemsg(mp);
- return 0;
- }
- }
-
- // Traffic for OnDemand interface and interface currently down?
- if ((myData->myInterfaceName == gOnDemandName) &&
- (gIsOnDemandUp == false) &&
- (filterAction != kFilterNoDial) ) {
- // set for OnDemand connection
- gIsOnDemandPending = true;
- }
-
- // Check if NAT for this interface
- match = false;
- // for (i=0; i<kNatNumDim; i++) {
- // if (myData->myInterfaceName == GetPortName(gNatTable[i])) {
- // // translate message
- // if ((datagram != nil) && GetNatOn(gNatTable[i]) && (myData->myInterfaceName)) {
- // result = Convert2Apparent(gNatTable[i], datagram, cp, kNATOptionIPMasq);
- // match = true;
- // }
- // break;
- // }
- // }
-
- if (!match) {
- // if no match try to NAT for DNS forwarding
- // if ((datagram != nil) && GetNatOn(gNatTable[0]) && gIsDNSForwarding) {
- // result = Convert2Apparent(gNatTable[0], datagram, cp, kNATOptionDNS);
- // }
- }
-
- }
-
- // flakeway - (1) delete packets
- if (gFlakePercent > 0) {
- flakeFactor = 100/gFlakePercent;
- flakeAction = false; // drop 1 in every flakeFactor packets
- if (gFlakePercent > 50) {
- flakeFactor = 100/(100-gFlakePercent);
- flakeAction = true; // pass 1 in every flakeFactor packets
- }
- myData->myPacketCount += 1;
- if ((myData->myPacketCount % flakeFactor) == 0) {
- // action for 1 in every N packets
- if (flakeAction == false) {
- // drop packet
- freemsg(mp);
- return 0;
- }
- }
- else {
- // action for other N-1 packets
- if (flakeAction) {
- // drop packet
- freemsg(mp);
- return 0;
- }
- }
- }
-
-
- // flakeway - (2) delay packets
- if (gFlakeLatency > 0) {
- // create a new timer message if needed
- if (!myData->timerMessage) {
- // try to allocate a timer message (q, size)
- myData->timerMessage = mi_timer_alloc(RD(q), kTimerSize);
- // schedule message
- if (myData->timerMessage) {
- // schedule for delay milliseconds
- mi_timer(myData->timerMessage, gFlakeLatency);
- }
- }
- // if we have a timer, queue message to process when timer expires
- if (myData->timerMessage) {
- putq(q, mp);
- return 0;
- }
- }
-
- /*
- * Now, we send it on. If we can't because of flow control, use
- * putq to put it on our queue and send it on.
- */
- if ( !bcanput(q->q_next, mp->b_band) )
- putq(q, mp);
- else
- putnext(q, mp);
-
- return 0;
- }
-
- int proxym_wproto(queue_t* q, mblk_t* mp)
- {
- Boolean doOutState = false;
- proxym_struct* myData = (proxym_struct*)RD(q)->q_ptr;
- /*
- * If the message block is not big enough - blow it away
- */
- if ( mp->b_wptr - mp->b_rptr < sizeof(long) )
- {
- freemsg(mp);
- return 0;
- }
- /*
- * Look at the incoming primitive message
- */
-
- switch ( ((union DL_primitives*)mp->b_rptr)->dl_primitive )
- {
- /*
- * For incoming data, let proxym_wdata handle it
- */
- case DL_UNITDATA_REQ:
- return proxym_wdata(q, mp);
-
- case DL_INFO_REQ:
- /*
- nextinfo = q->q_next->q_qinfo->qi_minfo;
- OTKernelPrintf( kOTPrintOnly, "DL_INFO_REQ, next write module is: %s.\n", nextinfo->mi_idname);
- nextinfo = RD(q)->q_next->q_qinfo->qi_minfo;
- OTKernelPrintf( kOTPrintOnly, "DL_INFO_REQ, next read module is: %s.\n", nextinfo->mi_idname);
- */
- //dprintf("\nproxym_wproto DL_INFO_REQ");
- break;
-
- case DL_BIND_REQ:
- /*
- * If we're not in the unbound state, give a
- * TOUTSTATE error. Otherwise, change our
- * state to DL_BIND_PENDING to flag that we're in
- * the process of binding, and pass the bind on.
- */
- if ( myData->myState != DL_UNBOUND )
- doOutState = true;
- else {
- myData->myState = DL_BIND_PENDING;
- }
- //dprintf("\nproxym_wproto DL_BIND_REQ");
- break;
-
- case DL_UNBIND_REQ:
- /*
- * If we're not in the DL_IDLE or DL_BIND_PENDING states,
- * give a TOUTSTATE error. Otherwise, pass the unbind on.
- */
- if ( myData->myState != DL_IDLE && myData->myState != DL_BIND_PENDING )
- doOutState = true;
- //dprintf("\nproxym_wproto DL_UNBIND_REQ");
- break;
-
- default:
- // pass it on
- //dprintf("\nproxym_wproto prim_type: %d", ((union DL_primitives*)mp->b_rptr)->dl_primitive);
- break;
- }
- if ( doOutState )
- {
- ReplyErrorAck(RD(q), mp, ((union DL_primitives*)mp->b_rptr)->dl_primitive,
- TOUTSTATE, 0);
- return 0;
- }
- /*
- * Here, we just pass the message block on to the next layer, or
- * queue it up till flow control is lifted.
- */
- if (mp->b_datap->db_type > QPCTL || canput(q->q_next) )
- putnext(q, mp);
- else
- putq(q, mp);
- return 0;
-
- }
-
- int proxym_wsrv(queue_t* q)
- {
- mblk_t* mp;
- proxym_struct* myData = (proxym_struct*)RD(q)->q_ptr;
-
- // if waiting for flake Latency just return
- if (myData->timerMessage != 0) return 0;
-
- /*
- * Send on downstream anything that was scheduled for flow control!
- */
- while ( (mp = getq(q)) != nilp(mblk_t) )
- {
- /*
- * If we're flow controlled, get out and we'll come back when the flow-
- * control lifts.
- */
- if ( !bcanput(q->q_next, mp->b_band) )
- {
- putbq(q, mp);
- return 0;
- }
- /*
- * Otherwise, send the data downstream, and get some more
- */
- //OTKernelPrintf( kOTPrintThenStop, "wsrv, putnext \n");
- putnext(q, mp);
- }
- return 0;
- }
-
- /*******************************************************************************
- ** Read-side process routines
- ********************************************************************************/
-
- int proxym_rdata(queue_t* q, mblk_t* mp)
- {
- proxym_struct* myData = (proxym_struct*)q->q_ptr;
- Boolean result = true;
- mblk_t* cp; // message block pointer
- UInt8* datagram; // datagram pointer
- SInt32 dataOffset;
- SInt32 dataCount;
- FilterEntry_t filterData;
- // UInt8 i;
- Boolean match;
- /*
- * If we're not ready for incoming data, just free it up
- */
- if ( myData->myState != DL_IDLE )
- {
- freemsg(mp);
- return 0;
- }
-
- /* ---------------------------------------------------------------------
- Here, we do whatever munging we're going to do on the incoming data,
- then send it on.
- Keep in mind that we call this routine from the proxy_rproto routine,
- so that the first block of the message might be an M_PROTO, and not
- data.
- --------------------------------------------------------------------- */
-
- // Check for IP data if protocol is specified
- if ((myData->myProtocolType == kProtocolTypeNone) ||
- (myData->myProtocolType == kProtocolTypeIP)) {
-
- // find datagram and containing message block (put in cp)
- datagram = FindRDatagram(q, mp, &cp, &dataOffset);
- // count data for monitor display
- if ((myData->myInterfaceName == gMonitorName) || (gMonitorName == 0)) {
- dataCount = proxy_CountMessage(mp) - dataOffset;
- OTAtomicAdd32(dataCount, &mstat.rCount);
- //OTKernelPrintf( kOTPrintOnly, "proxy_rdata rCount is: %d.\n", mstat.rCount);
- }
-
- //
- // for inbound packets: NAT first, then filter
- //
- // Check if NAT for this interface
- match = false;
- // for (i=0; i<kNatNumDim; i++) {
- // if (myData->myInterfaceName == GetPortName(gNatTable[i])) {
- // // translate message
- // if ((datagram != nil) && GetNatOn(gNatTable[i]) && (myData->myInterfaceName)) {
- // match = true;
- // result = Convert2Actual(gNatTable[i], datagram, cp, kNATOptionIPMasq);
- // // if no translation found and no exposed host
- // if (result == kNATActionReject) {
- // // kill it
- // freemsg(mp);
- // return 0;
- // }
- // }
- // break;
- // }
- // }
- // if no match, perform local translation if any
- if (!match) {
- // translate message
- /*
- if ((datagram != nil) && GetNatOn(gNatTable[0])) {
- if (gIsTRCableModem) {
- // TR Cable Modem
- // result = Convert2Actual(gNatTable[0], datagram, cp, kNATOptionIPMasq);
- }
- else
- if (gIsLocalNatOn) {
- // result = Convert2Actual(gNatTable[0], datagram, cp, kNATOptionLocal);
- //if (result && !gIsTRCableModem) {
- // // for Local NAT, direct response via gateway
- // result = Convert2Apparent(gNatTable[0], datagram, cp, kNATOptionLocal);
- //}
- }
- else
- if (gIsDNSForwarding) {
- // DNS Forwarding
- // result = Convert2Actual(gNatTable[0], datagram, cp, kNATOptionDNS);
- }
- }
- */
- }
-
- // Process IP filtering
- if (datagram != nil) {
- UInt8 filterAction;
- filterData.portName = myData->myInterfaceName;
- filterData.flags = kFlagDirectionRead;
- filterAction = FilterPacket(datagram, cp, &filterData);
- if (filterAction == kFilterReject) {
- // kill it
- freemsg(mp);
- return 0;
- }
- }
-
- }
-
- /*
- * Now, we send it on. If we can't because of flow control, use
- * putq to put it on our queue and send it on later.
- */
- if ( !bcanput(q->q_next, mp->b_band) )
- putq(q, mp);
- else
- putnext(q, mp);
-
- return 0;
- }
-
- int proxym_rproto(queue_t* q, mblk_t* mp)
- {
- Boolean doOutState = false;
- proxym_struct* myData = (proxym_struct*)q->q_ptr;
- dl_info_ack_t* myInfo;
- // UInt8* dp;
- /*
- * If the message block is not big enough - blow it away
- */
- if ( mp->b_wptr - mp->b_rptr < sizeof(long) )
- {
- freemsg(mp);
- return 0;
- }
- /*
- * Look at the incoming primitive message
- */
- switch ( ((union DL_primitives*)mp->b_rptr)->dl_primitive )
- {
- /*
- * For incoming data, let proxy_rdata handle it
- */
- case DL_UNITDATA_IND:
- return proxym_rdata(q, mp);
-
- case DL_INFO_ACK:
- myInfo = (dl_info_ack_t*)mp->b_rptr;
- //dprintf("\nproxym_rproto DL_INFO_ACK");
- /*
- dprintf("\n dl_max_sdu: %d", myInfo->dl_max_sdu);
- dprintf("\n dl_min_sdu: %d", myInfo->dl_min_sdu);
- dprintf("\n dl_addr_length: %d", myInfo->dl_addr_length);
- dprintf("\n dl_mac_type: %d", myInfo->dl_mac_type);
- dprintf("\n dl_current_state: %d", myInfo->dl_current_state);
- dprintf("\n dl_sap_length: %d", myInfo->dl_sap_length);
- dprintf("\n dl_service_mode: %d", myInfo->dl_service_mode);
- dprintf("\n dl_qos_length: %d", myInfo->dl_qos_length);
- dprintf("\n dl_qos_offset: %d", myInfo->dl_qos_offset);
- dprintf("\n dl_qos_range_length: %d", myInfo->dl_qos_range_length);
- dprintf("\n dl_qos_range_offset: %d", myInfo->dl_qos_range_offset);
- dprintf("\n dl_provider_style: %d", myInfo->dl_provider_style);
- dprintf("\n dl_addr_offset: %d", myInfo->dl_addr_offset);
- dprintf("\n dl_version: %d", myInfo->dl_version);
- dprintf("\n dl_brdcst_addr_length: %d", myInfo->dl_brdcst_addr_length);
- dprintf("\n dl_brdcst_addr_offset: %d", myInfo->dl_brdcst_addr_offset);
- dprintf("\n dl_growth: %d", myInfo->dl_growth);
- dp = (UInt8*)myInfo;
- dprintf("\n dl_sap_addr: ");
- dprintmem(&dp[myInfo->dl_addr_offset], myInfo->dl_addr_length);
- */
- break;
-
- /*
- * Here, a bind request succeeded.
- */
- case DL_BIND_ACK: {
- // remember what protocol we are bound to
- UInt32 sap;
- dl_bind_ack_t* bindAck;
- bindAck = (dl_bind_ack_t*)mp->b_rptr;
- sap = bindAck->dl_sap;
- if ((kMinDIXSAP <= sap) && (sap <= kMaxDIXSAP)) {
- myData->myProtocolType = bindAck->dl_sap & 0xFFFF;
- //dprintf("\nproxym_rproto DL_BIND_ACK, protocol type: %x", myData->myProtocolType);
- }
- // update endpoint state
- myData->myState = DL_IDLE;
- break;
- }
- /*
- * Handle any error acks that come back
- */
- case DL_ERROR_ACK:
- {
- switch ( ((dl_error_ack_t*)mp->b_rptr)->dl_error_primitive )
- {
- /*
- * If the unbind failed, then we are not unbound either.
- * Send the error on up to the client.
- */
- case DL_UNBIND_REQ:
- myData->myState = DL_IDLE;
- //dprintf("\nproxym_rproto DL_ERROR_ACK on DL_UNBIND_REQ");
- break;
-
- /*
- * If the bind failed, we fall back to the unbound state
- */
- case DL_BIND_REQ:
- myData->myState = DL_UNBOUND;
- //dprintf("\nproxym_rproto DL_ERROR_ACK on DL_BIND_REQ");
- break;
-
-
- /*
- * Any error acks we don't understand just pass on
- */
- default:
- //dprintf("\nproxym_rproto DL_ERROR_ACK on prim: %d", ((dl_ok_ack_t*)mp->b_rptr)->dl_correct_primitive);
- break;
- }
- break;
- }
-
- /*
- * Handle any OK acks that come back
- */
- case DL_OK_ACK:
- {
- switch ( ((dl_ok_ack_t*)mp->b_rptr)->dl_correct_primitive )
- {
- /*
- * If the unbind is OK, we are no longer unbound.
- */
- case DL_UNBIND_REQ:
- myData->myState = DL_UNBOUND;
- //dprintf("\nproxym_rproto DL_OK_ACK on DL_UNBIND_REQ");
- break;
-
- case DL_BIND_REQ:
- myData->myState = DL_IDLE;
- //dprintf("\nproxym_rproto DL_OK_ACK on DL_BIND_REQ");
- break;
-
- /*
- * Any error acks we don't understand just pass on
- */
- default:
- //dprintf("\nproxym_rproto DL_OK_ACK on prim: %d", ((dl_ok_ack_t*)mp->b_rptr)->dl_correct_primitive);
- break;
- }
- break;
- }
-
- /*
- * Anything else we don't understand, just send it on
- */
- default:
- //dprintf("\nproxym_rproto prim_type: %d", ((union DL_primitives*)mp->b_rptr)->dl_primitive);
- break;
- } /*
- * Here, we just pass the message block on to the next layer, or
- * queue it up till flow control is lifted.
- */
- if (mp->b_datap->db_type > QPCTL || canput(q->q_next) )
- putnext(q, mp);
- else
- putq(q, mp);
- return 0;
- }
-
- int proxym_rsrv(queue_t* q)
- {
- mblk_t* mp;
- /*
- * Send on up anything that was scheduled for flow control!
- */
- while ( (mp = getq(q)) != nilp(mblk_t) )
- {
- /*
- * If we're flow controlled, get out and we'll come back when the flow-
- * control lifts.
- */
- if ( !bcanput(q->q_next, mp->b_band) )
- {
- putbq(q, mp);
- return 0;
- }
- /*
- * Otherwise, send the data upstream, and get some more
- */
- putnext(q, mp);
- }
- return 0;
- }
-
- #pragma mark • generic support functions •
-
- /*******************************************************************************
- ** ReuseMessage
- **
- ** Determine if we can reuse an mblk_t*. If not, reallocate one.
- ********************************************************************************/
-
- mblk_t* ReuseMessage(mblk_t* mp, size_t size)
- {
- if ( mp != nilp(mblk_t) )
- {
- if ( mp->b_cont != nilp(mblk_t) )
- {
- freemsg(mp->b_cont);
- mp->b_cont = nilp(mblk_t);
- }
- mp->b_rptr = mp->b_datap->db_base;
- mp->b_wptr = mp->b_rptr;
- if ( mp->b_datap->db_ref == 1 &&
- mp->b_datap->db_lim - mp->b_rptr >= size )
- return mp;
- freemsg(mp);
- }
- return allocb(size, BPRI_LO);
- }
-
- /*******************************************************************************
- ** proxy_error
- **
- ** Process a fatal error
- ********************************************************************************/
-
- static void retry_error(long arg)
- {
- proxym_struct* myData = (proxym_struct*)((queue_t*)arg)->q_ptr;
- (void)proxy_error((queue_t*)arg, NULL, myData->myError);
- }
-
- int proxy_error(queue_t* rdq, mblk_t* mp, int error)
- {
- proxym_struct* myData = (proxym_struct*)rdq->q_ptr;
- myData->myState = DL_UNATTACHED; // a bad state (any data will be ignored)
- /*
- * Try to reuse the incoming message block.
- */
- mp = ReuseMessage(mp, 1);
- /*
- * If we can't get one, use bufcall to try this again
- * when memory is available.
- */
- if ( mp == nilp(mblk_t) )
- {
- myData->myError = error;
- bufcall(1, BPRI_HI, (bufcall_t)retry_error, (long)rdq);
- return 0;
- }
- mp->b_wptr = mp->b_rptr + 1;
- mp->b_rptr[0] = (unsigned char)error;
- mp->b_datap->db_type = M_ERROR;
- putnext(rdq, mp);
- return 0;
- }
-
- /*******************************************************************************
- ** ReplyErrorAck
- ********************************************************************************/
-
- static void retry_ack(long arg)
- {
- error_struct* es = (error_struct*)arg;
- int xtiErr = es->xtiErr;
- int macErr = es->macErr;
- long reqType = es->reqType;
- queue_t* rdq = es->rdq;
- if ( es->allocd )
- OTFreeMem(es);
- ReplyErrorAck(rdq, NULL, reqType, xtiErr, macErr);
- }
-
- void ReplyErrorAck(queue_t* rdq, mblk_t* mp, long reqType, int xtiErr, int macErr)
- {
- proxym_struct* myData = (proxym_struct*)rdq->q_ptr;
- mp = ReuseMessage(mp, sizeof(dl_error_ack_t));
- if ( mp == nilp(mblk_t) )
- {
- /*
- * If we can't get a message block, either allocate an error_struct
- * or use the one we have stored in our data.
- */
- error_struct* es;
- if ( myData->errInUse )
- {
- es = (error_struct*)OTAllocMem(sizeof(error_struct*));
- if ( es != NULL )
- es->allocd = true;
- }
- else
- {
- myData->errInUse = true;
- es = &myData->myErrorStruct;
- }
- /*
- * If we could get an error_struct, try using bufcall. If that fails -
- * we're hosed. Use proxy_error to kill the stream
- */
- if ( es != NULL )
- {
- es->reqType = reqType;
- es->xtiErr = xtiErr;
- es->macErr = macErr;
- es->rdq = rdq;
- if ( bufcall(sizeof(dl_error_ack_t), BPRI_HI, (bufcall_t)retry_ack,
- (long)es) != 0 )
- {
- if ( es->allocd )
- OTFreeMem(es);
- es = NULL;
- }
- }
- if ( es == NULL )
- (void)proxy_error(rdq, NULL, ENOSR);
- } else {
- mp->b_wptr = mp->b_rptr + sizeof(dl_error_ack_t);
- ((dl_error_ack_t*)mp->b_rptr)->dl_primitive = DL_ERROR_ACK;
- ((dl_error_ack_t*)mp->b_rptr)->dl_error_primitive = reqType;
- ((dl_error_ack_t*)mp->b_rptr)->dl_errno = xtiErr;
- ((dl_error_ack_t*)mp->b_rptr)->dl_unix_errno = macErr;
- mp->b_datap->db_type = M_PCPROTO;
- putnext(rdq, mp);
- }
- }
-
-
- // ---------------------------------------------------------------------------------
- // • proxy count message
- // ---------------------------------------------------------------------------------
- // Count data characters in message
- SInt32 proxy_CountMessage(mblk_t* mp)
- {
- mblk_t* cp = mp; // local copy of mp
- SInt32 count = 0;
-
- // don't count first block if it's an M_PROTO (such as DL_UNITDATA_REQ/IND)
- if ( cp->b_datap->db_type == M_PROTO ) cp = cp->b_cont;
-
- // count characters in first block and any continuation blocks
- while (cp != nilp(mblk_t)) {
- count += (UInt32)cp->b_wptr - (UInt32)cp->b_rptr;
- cp = cp->b_cont;
- }
- return count;
- }
-
-
- // ---------------------------------------------------------------------------------
- // • Hash Name
- // ---------------------------------------------------------------------------------
- // Hash module name to a 32-bit value
- // The hashed value is used to select which drivers we will monitor or translate
- UInt32 HashName(char* inName)
- {
- UInt32 result = 0;
- UInt32 part = 0;
- UInt32 index = 0;
-
- while (inName[index] != 0) {
- part = result >> 24; // get left most byte
- result = result << 8; // shift left 8-bits
- result += inName[index]; // add next character in name
- result += part << 5; // add back anything shifted out
- result += part << 19;
- index += 1; // increment to get next character
- }
-
- return result;
- }
-
-
- // ---------------------------------------------------------------------------------
- // • FindWDatagram
- // ---------------------------------------------------------------------------------
- // Find start of IP datagram
- // Returns nil if none found
- UInt8*
- FindWDatagram(queue_t* q, mblk_t* mp, mblk_t** outMp, SInt32* dataOffset)
- {
- mblk_t* cp; // message block pointer
- UInt8* datagram;
- proxym_struct* myData = (proxym_struct*)RD(q)->q_ptr;
-
- // find start of datagram
- datagram = nil;
- cp = mp; // local copy of mp
- *dataOffset = 0;
-
- if ( cp->b_datap->db_type == M_PROTO ) {
- // first block is an M_PROTO
- // DL_UNITDATA_REQ/IND with datagram in attached M_DATA blocks
- cp = cp->b_cont;
- if (cp != nilp(mblk_t)) {
- // pull up message if necessary
- if (cp->b_cont != nil) pullupmsg(cp, -1);
- datagram = cp->b_rptr;
- }
- } else {
- // first block is M_DATA
- // Mentat Fastpath M_DATA message with Link Layer header
- // We listen for the DL_IOC_HDR_INFO ack and examine the
- // Header to determine its length. See Mentat 3-61.
- // pull up message if necessary
- UInt32 hLen = myData->myFastPathHeaderSize;
- if (cp->b_cont != nil) pullupmsg(cp, -1);
- datagram = cp->b_rptr;
-
- // use FastPathHeaderSize if reasonable
- if ((hLen > 0) && // size is specified
- ((datagram[hLen] & 0xF0) == 0x40)) { // points to start of IP V4 datagram
- datagram = &datagram[hLen];
- *dataOffset = hLen;
- }
- else {
- // fallback to look for start of datagram
- if ((datagram[0] & 0xF0) != 0x40) {
- int i;
- for (i=14; i>=0; i-=2) {
- if (datagram[i] == 0x45) {
- datagram = &datagram[i];
- *dataOffset = i;
- break;
- }
- }
- }
- }
- }
-
- *outMp = cp;
- return datagram;
- }
-
-
- // ---------------------------------------------------------------------------------
- // • FindRDatagram
- // ---------------------------------------------------------------------------------
- // Find start of IP datagram
- // Returns nil if none found
- UInt8*
- FindRDatagram(queue_t* q, mblk_t* mp, mblk_t** outMp, SInt32* dataOffset)
- {
- mblk_t* cp; // message block pointer
- UInt8* datagram;
-
- // find start of datagram
- datagram = nil;
- cp = mp; // local copy of mp
- *dataOffset = 0;
-
- if ( cp->b_datap->db_type == M_PROTO ) {
- // first block is an M_PROTO
- // DL_UNITDATA_REQ/IND with datagram in attached M_DATA blocks
- cp = cp->b_cont;
- if (cp != nilp(mblk_t)) {
- // pull up message if necessary
- if (cp->b_cont != nil) pullupmsg(cp, -1);
- datagram = cp->b_rptr;
- }
- } else {
- // first block is M_DATA
- // Mentat Fastpath M_DATA message with no link layer header (read side)
- // pull up message if necessary
- if (cp->b_cont != nil) pullupmsg(cp, -1);
- datagram = cp->b_rptr;
- }
-
- *outMp = cp;
- return datagram;
- }
-
-
- // ---------------------------------------------------------------------------------
- // • FilterPacket
- // ---------------------------------------------------------------------------------
- // Perform IP filtering
- // Include NetBIOS filtering as standard for On Demand Interface
- // Look for UDP from source ports 137, 138, and 139
- UInt8
- FilterPacket(UInt8* datagram, mblk_t* mp, FilterEntry_t* filterData)
- {
- ip_header_t* ipHeader;
- udp_header_t* udpHeader;
- tcp_header_t* tcpHeader;
- icmp_header_t* icmpHeader;
- UInt32 size;
- UInt8 ipHeaderLen;
- UInt8 result;
-
- do {
- // default to rejct if unrecognized
- result = kFilterReject;
-
- size = (UInt32)mp->b_wptr - (UInt32)datagram;
- // make sure we got enough data for IP header
- if (size < 20) {
- break;
- }
-
- // setup to access IP Header
- ipHeader = (ip_header_t*)datagram;
-
- // check that we have a valid datagram
- // Is it V4?
- if ((ipHeader->hlen & 0xF0) != 0x40) {
- break;
- }
- ipHeaderLen = (ipHeader->hlen & 0x0F) << 2; // in bytes
- // *** optional, verify header checksum
- // if (IpSum( (UInt16*)&datagram[0], (UInt16*)&datagram[ipHeaderLen] ) != 0xFFFF) {
- // break;
- // }
-
- // get IP address
- filterData->sourceNet.address = ipHeader->srcAddress;
- filterData->destNet.address = ipHeader->dstAddress;
- if (filterData->portName == gOnDemandName) {
- gOnDemandSrcAddress = ipHeader->srcAddress; // remember on demand src
- }
- // get protocol
- filterData->protocol = ipHeader->protocol;
-
- result = kFilterPass;
- // Handle each protocol as a separate case
- switch (ipHeader->protocol) {
- case kProtocolUDP:
- // make sure we got enough data for UDP header
- if (size < (ipHeaderLen + 8)) break;
- // setup access to UDP header
- udpHeader = (udp_header_t*)&datagram[ipHeaderLen];
- // get UDP protocol ports
- filterData->sourcePorts.lo = udpHeader->srcPort;
- filterData->destPorts.lo = udpHeader->dstPort;
- // filter NetBIOS DNS querries
- if ((filterData->portName == gOnDemandName) && // on demand interface
- ((filterData->flags & kFlagDirectionRead) == 0)) { // write side
- if ((udpHeader->srcPort == 137) ||
- (udpHeader->srcPort == 138) ||
- (udpHeader->srcPort == 139)) {
- result = kFilterNoDial;
- break;
- }
- }
- // process through filter table
- // result = FilterDatagram(gFilterTable, filterData);
- break;
-
- case kProtocolTCP:
- // make sure we got enough data for TCP header
- if (size < (ipHeaderLen + 20)) break;
- // setup access to TCP header
- tcpHeader = (tcp_header_t*)&datagram[ipHeaderLen];
- // get TCP protocol ports
- filterData->sourcePorts.lo = tcpHeader->srcPort;
- filterData->destPorts.lo = tcpHeader->dstPort;
- // get TCP Ack bit
- if (tcpHeader->code & kCodeACK) {
- filterData->flags |= kFlagAck;
- }
- // process through filter table
- // result = FilterDatagram(gFilterTable, filterData);
- if ((result == kFilterPass) && (tcpHeader->code & kCodeFIN)) result = kFilterNoDial;
- break;
-
- case kProtocolICMP:
- // make sure we got the whole datagram
- if (size < ipHeader->totalLength) break;
- // setup access to ICMP header
- icmpHeader = (icmp_header_t*)&datagram[ipHeaderLen];
- // use ICMP type in place of protocol port
- filterData->sourcePorts.lo = icmpHeader->type;
- filterData->destPorts.lo = icmpHeader->code;
- // process through filter table
- // result = FilterDatagram(gFilterTable, filterData);
- // acquire flakeway parameters
- {
- enum { kMagic = 'sqlh' };
- UInt32 magic;
- OTMemmove(&magic, &icmpHeader->data[0], 4); // dst, src, nbytes
- if (magic == kMagic) {
- OTMemmove(&gFlakePercent, &icmpHeader->data[4], 2);
- OTMemmove(&gFlakeLatency, &icmpHeader->data[6], 2);
- dprintf("\nFlakeWay drop %d, delay %d", gFlakePercent, gFlakeLatency);
- }
- }
- break;
-
- default:
- // no port information available
- filterData->sourcePorts.lo = 0;
- filterData->destPorts.lo = 0;
- // process through filter table
- // result = FilterDatagram(gFilterTable, filterData);
- break;
- }
- } while (false);
-
- return result;
- }
-
- #pragma mark • Macintosh Install Info •
-
- /* ------------------------------------------------------------------------
-
- THESE FUNCTIONS AND DATA STRUCTURES ARE SPECIFIC TO THE MACINTOSH IMPLEMENTATION
- OF STREAMS. THESE ROUTINES WOULD NOT EXIST IN OTHER STREAMS ENVIRONMENTS.
-
- WHEN PORTING OTHER STREAMS CODE TO THE MACINTOSH, THESE ROUTINES AND DATA
- STRUCTURES MUST BE ADDED.
-
- ------------------------------------------------------------------------ */
- install_info* GetOTProxymInstallInfo();
- Boolean InitProxymStreamModule(void* cookie);
- void TerminateProxymStreamModule();
-
- /*******************************************************************************
- ** install_info structure, and the GetInstallInfo function
- **
- ** This is the structure that tells Open Transport about your module. OT calls
- ** your "GetInstallInfo" function to get this information.
- **
- ********************************************************************************/
-
- install_info* GetOTProxymInstallInfo()
- {
- return &proxymInstallInfo;
- }
-
- /*******************************************************************************
- ** This is the function that will be called the first time that this code
- ** is loaded. It is guaranteed that this function is call at SystemTask time
- ** on the Macintosh.
- ********************************************************************************/
-
- Boolean InitProxymStreamModule(void* cookie)
- {
- /* Do any machine specific initialization stuff you need to */;
- gProxymListHead = NULL;
- proxymRefCountAdjusted = false;
- //dprintf("\nInitProxymStreamModule");
- return true;
- }
-
- // This function will be called when Open Transport removes the last
- // instance of a module or driver from the system.
- void TerminateProxymStreamModule()
- {
- }
-
- // ===========================================================================
-
- #pragma mark -
- #pragma mark ••• Proxy STREAMS Driver •••
- #pragma mark • module structure & procedures •
-
-
- /*******************************************************************************
- ** Open routine
- ********************************************************************************/
-
- typedef struct proxy_struct
- {
- UInt16 myError;
- UInt16 myState;
- mblk_t* timerMessage;
- UInt32 timerSequenceNumber;
- UInt32 timerUnAckCount;
- Boolean monitorIsOnFlag;
- } proxy_struct;
-
- int proxy_open(queue_t* rdq, dev_t* devp, int flag, int sflag, cred_t* credp)
- {
- int err;
- proxy_struct* myData;
-
- // adjust ref count so we don't unload until companion module is free
- if ( OTCompareAndSwap32(1, 2, &proxyInstallInfo.ref_count) )
- proxyRefCountAdjusted = true;
-
- err = mi_open_comm(&gProxyListHead, sizeof(proxy_struct),
- rdq, devp, flag, sflag, credp);
-
- if (err == 0) {
- // Set my state in my data structure
- myData = (proxy_struct*)rdq->q_ptr;
- myData->myState = TS_UNBND;
- myData->timerMessage = nilp(mblk_t);
- myData->timerSequenceNumber = 0;
- myData->timerUnAckCount = 0;
- myData->monitorIsOnFlag = false;
- }
-
- // return result
- return err;
- }
-
-
- /*******************************************************************************
- ** Close routine
- ********************************************************************************/
-
- int proxy_close(queue_t* rdq, int flags, cred_t* credP)
- {
- int err;
- proxy_struct* myData = (proxy_struct*)rdq->q_ptr;
-
- // release our timer message if any
- //OTKernelPrintf( kOTPrintOnly, "proxy_close closing driver.\n");
- if (myData->monitorIsOnFlag) {
- myData->monitorIsOnFlag = false;
- // if timerMessage is pending, cancel it
- if (myData->timerMessage) {
- mi_timer_free(myData->timerMessage);
- myData->timerMessage = nilp(mblk_t);
- }
- }
-
- err = mi_close_comm(&gProxyListHead, rdq);
-
- // adjust ref count so we don't unload until companion module is free
- if (proxymInstallInfo.ref_count <= 1) { // if done with companion
- // if I'm done, and my ref_count was adjusted,
- // decrement my ref_count so it can go to zero and
- if (proxyRefCountAdjusted) {
- if ( OTCompareAndSwap32(2, 1, &proxyInstallInfo.ref_count) ) {
- proxymInstallInfo.ref_count = 0; // set companion to zero ???
- proxyRefCountAdjusted = false;
- }
- }
- }
-
- // return result
- return err;
- }
-
- /*******************************************************************************
- ** Write-side put routine
- ********************************************************************************/
-
- int proxy_wput(queue_t* q, mblk_t* mp)
- {
- Boolean result;
- UInt8 index;
- /*
- * Process the incoming message from the client
- */
- switch (mp->b_datap->db_type)
- {
- /*
- * Process a signal message - Under Open Transport, this is normally
- * a timer message. If not a timer message for myself, pass it on.
- */
- case M_PCSIG:
- break;
- /*
- * Undocumented message type - just pass it on.
- */
- case M_HPDATA:
- break;
- /*
- * You will get one of these if you use M_COPYIN. If it's not for
- * yourself, pass it on.
- */
- case M_IOCDATA:
- break;
- /*
- * These are messages for future expansion. If not understood,
- * pass them on
- */
- case M_PCRSE:
- case M_RSE:
- break;
-
- /*
- * Request to flush queues.
- * Since we're a driver, we have to do a little more work
- */
- case M_FLUSH:
- if ( mp->b_rptr[0] & FLUSHW)
- {
- if ( (mp->b_rptr[0] & FLUSHBAND) && mp->b_wptr - mp->b_rptr == 2 )
- flushband(q, mp->b_rptr[1], FLUSHALL);
- else
- flushq(q, FLUSHALL);
- }
- if ( mp->b_rptr[0] & FLUSHR )
- {
- if ( (mp->b_rptr[0] & FLUSHBAND) && mp->b_wptr - mp->b_rptr == 2 )
- flushband(RD(q), mp->b_rptr[1], FLUSHALL);
- else
- flushq(RD(q), FLUSHALL);
- mp->b_rptr[0] &= ~FLUSHW;
- qreply(q, mp);
- return 0;
- }
- break;
-
- /*
- * These messages are rarely uses, but you may need to process them.
- */
- case M_STOP:
- case M_START:
- case M_STOPI:
- case M_STARTI:
- case M_READ:
- case M_BREAK:
- case M_DELAY:
- case M_CTL:
- break;
-
- // Here, we process any IOCTLs that we might support.
- case M_IOCTL:
- {
- struct iocblk* iocp = (struct iocblk*)mp->b_rptr;
- //OTKernelPrintf( kOTPrintOnly, "Entering wput IOCTL, ioc_cmd: %x.\n", iocp->ioc_cmd);
- proxy_struct* myData = (proxy_struct*)q->q_ptr;
-
- switch ( iocp->ioc_cmd )
- {
- case I_MonitorOn:
- // IOCTL requesting Monitor events
-
- // Acknowledge client is handling events
- myData->timerUnAckCount = 0; // reset unacknowledged counter
-
- // Check if companion stream module has been configured
- if (proxymInstallInfo.ref_count == 0) {
- // companion module has not been configured, nothing to monitor.
- // respond with M_IOCACK, monitor pending
- mp->b_datap->db_type = M_IOCACK; // set message type
- iocp->ioc_error = 0;
- iocp->ioc_count = 0;
- iocp->ioc_rval = I_MonitorPending;
- qreply(q, mp);
- return 0;
- }
-
- // If monitoring is not already turned on
- if ( !myData->monitorIsOnFlag ) {
-
- // set state to generate events
- //OTKernelPrintf( kOTPrintOnly, "Proxy IOCTL: I_SetMonitorOn.\n");
- myData->monitorIsOnFlag = true;
-
- // create a new timer message
- // try to allocate a timer message (q, size)
- myData->timerMessage = mi_timer_alloc(RD(q), kTimerSize);
- // schedule message
- if (myData->timerMessage) {
- // re-initialize stat counters
- proxy_GetTimedStat(q, nil, nil, nil);
- // schedule for delay milliseconds
- mi_timer(myData->timerMessage, kTimerDelay);
- }
- }
-
- // respond with M_IOCACK
- mp->b_datap->db_type = M_IOCACK; // set message type
- iocp->ioc_error = 0;
- iocp->ioc_count = 0;
- iocp->ioc_rval = I_MonitorStart;
- qreply(q, mp);
- return 0;
- case I_MonitorOff:
- // IOCTL to turn off Monitor events
- // set state to turn off events
- if (myData->monitorIsOnFlag) {
- myData->monitorIsOnFlag = false;
- // if timerMessage is pending, cancel it
- if (myData->timerMessage) {
- mi_timer_free(myData->timerMessage);
- myData->timerMessage = nilp(mblk_t);
- }
- }
- // respond with M_IOCACK
- mp->b_datap->db_type = M_IOCACK; // set message type
- iocp->ioc_error = 0;
- iocp->ioc_count = 0;
- iocp->ioc_rval = I_MonitorPause;
- qreply(q, mp);
- return 0;
-
- case I_SetMonitorName:
- // IOCTL to set Monitor Port Name
- {
- mblk_t* mp2;
- proxy_name_t* proxyParam;
-
- // get Continued message block with IOCTL data
- // is there any data?
- if (iocp->ioc_count >= sizeof(proxy_name_t)) {
- mp2 = mp->b_cont;
- proxyParam = (proxy_name_t*)mp2->b_rptr;
- // save hashed interface name
- gMonitorName = proxyParam->portNameHash;
- //OTKernelPrintf( kOTPrintThenStop, "IOCTL Set on demand name, param: %x \n", gInterfaceName);
- }
- }
- // respond with M_IOCACK
- mp->b_datap->db_type = M_IOCACK; // set message type
- iocp->ioc_error = 0;
- iocp->ioc_count = 0;
- iocp->ioc_rval = kProxyNoError;
- qreply(q, mp);
- return 0;
-
- case I_SetPortName:
- // IOCTL to set Port Name for NAT
- {
- mblk_t* mp2;
- proxy_name_t* proxyParam;
- // UInt8 i;
-
- result = false;
- // get Continued message block with IOCTL data
- // is there any data?
- if (iocp->ioc_count >= sizeof(proxy_name_t)) {
- mp2 = mp->b_cont;
- proxyParam = (proxy_name_t*)mp2->b_rptr;
- // look for an available NAT table or already assigned
- /*
- for (i=0; i<kNatNumDim; i++) {
- if ((GetPortName(gNatTable[i]) == 0) ||
- (GetPortName(gNatTable[i]) == proxyParam->portNameHash)) {
- // Init the NAT table to get ready for use
- // InitTable(gNatTable[i]);
- // set port name to indicate table in use
- // SetPortName(gNatTable[i], proxyParam->portNameHash);
- result = true;
- break;
- }
- }
- */
- // save hashed interface name
- // gInterfaceName = HashName(proxyInterfaceName->name);
- //OTKernelPrintf( kOTPrintThenStop, "IOCTL Set interface name, param: %x \n", gInterfaceName);
- }
- }
- // respond with M_IOCACK
- mp->b_datap->db_type = M_IOCACK; // set message type
- iocp->ioc_error = 0;
- iocp->ioc_count = 0;
- iocp->ioc_rval = kProxyNoError;
- if (!result) iocp->ioc_rval = kProxyTableError;
- qreply(q, mp);
- return 0;
- case I_GetPortNames:
- // IOCTL to get Port Names for NAT
- {
- mblk_t* mp2;
- proxy_names_t* proxyParam;
- // UInt8 i;
-
- result = false;
- // get Continued message block with IOCTL data
- // is there any data?
- if (iocp->ioc_count >= sizeof(proxy_names_t)) {
- mp2 = mp->b_cont;
- proxyParam = (proxy_names_t*)mp2->b_rptr;
- // look for an available NAT table
- // for (i=0; i<kNatNumDim; i++) {
- // proxyParam->NatPortName[i] = GetPortName(gNatTable[i]);
- // proxyParam->NatIPAddr[i] = GetNatNetwork(gNatTable[i])->address;
- // }
- result = true;
- }
- }
- // respond with M_IOCACK
- mp->b_datap->db_type = M_IOCACK; // set message type
- iocp->ioc_error = 0;
- //iocp->ioc_count = 0; // leave as passed in
- iocp->ioc_rval = kProxyNoError;
- if (!result) iocp->ioc_rval = kProxyTableError;
- qreply(q, mp);
- return 0;
- case I_SetApparentAddress:
- // IOCTL to set Apparent Address for NAT
- {
- FilterTableData_t* filterData;
- mblk_t* mp2;
- proxy_network_t* proxyParam;
- // UInt8 i;
-
- // get Continued message block with IOCTL data
- // is there any data?
- if (iocp->ioc_count >= sizeof(proxy_network_t)) {
- mp2 = mp->b_cont;
- proxyParam = (proxy_network_t*)mp2->b_rptr;
- // find corresponding NAT table
- // for (i=0; i<kNatNumDim; i++) {
- // if (proxyParam->portNameHash == GetPortName(gNatTable[i])) {
- // // set address
- // SetNatNetwork(gNatTable[i], &proxyParam->net);
- // break;
- // }
- // }
- // save as dynamic address in filter table
- filterData = (FilterTableData_t*)&gFilterTable[0];
- filterData->ipAddress = proxyParam->net.address;
- //OTKernelPrintf( kOTPrintThenStop, "IOCTL Set Apparent Address, param: %x \n", proxyParam->array[0]);
- }
- }
- // respond with M_IOCACK
- mp->b_datap->db_type = M_IOCACK; // set message type
- iocp->ioc_error = 0;
- iocp->ioc_count = 0;
- iocp->ioc_rval = kProxyNoError;
- qreply(q, mp);
- return 0;
- case I_SetExposedHost:
- // IOCTL to set Exposed Host address for NAT
- {
- mblk_t* mp2;
- proxy_network_t* proxyParam;
- // UInt8 i;
-
- // get Continued message block with IOCTL data
- // is there any data?
- if (iocp->ioc_count >= sizeof(proxy_network_t)) {
- mp2 = mp->b_cont;
- proxyParam = (proxy_network_t*)mp2->b_rptr;
- // find corresponding NAT table
- // for (i=0; i<kNatNumDim; i++) {
- // if (proxyParam->portNameHash == GetPortName(gNatTable[i])) {
- // // set address
- // SetExposedHost(gNatTable[i], proxyParam->net.address);
- // break;
- // }
- // }
- }
- }
- // respond with M_IOCACK
- mp->b_datap->db_type = M_IOCACK; // set message type
- iocp->ioc_error = 0;
- iocp->ioc_count = 0;
- iocp->ioc_rval = kProxyNoError;
- qreply(q, mp);
- return 0;
- case I_SetActualNetwork:
- // IOCTL to set Actual Network that should not be translated
- {
- mblk_t* mp2;
- proxy_network_t* proxyParam;
- // UInt8 i;
-
- // get Continued message block with IOCTL data
- // is there any data?
- if (iocp->ioc_count >= sizeof(proxy_network_t)) {
- mp2 = mp->b_cont;
- proxyParam = (proxy_network_t*)mp2->b_rptr;
- // find corresponding NAT table
- // for (i=0; i<kNatNumDim; i++) {
- // if (proxyParam->portNameHash == GetPortName(gNatTable[i])) {
- // // set actual network
- // SetActualNetwork(gNatTable[i], &proxyParam->net);
- // break;
- // }
- // }
- // setup to access NAT parameters
- // data = (tableData_t*)&gNatTable[0];
- // data->actualNetwork.address = proxyParam->address;
- // data->actualNetwork.mask = proxyParam->mask;
- //OTKernelPrintf( kOTPrintOnly, "IOCTL Set Actual Network: %x \n", proxyParam->address);
- }
- }
- // respond with M_IOCACK
- mp->b_datap->db_type = M_IOCACK; // set message type
- iocp->ioc_error = 0;
- iocp->ioc_count = 0;
- iocp->ioc_rval = kProxyNoError;
- qreply(q, mp);
- return 0;
- case I_NatOn:
- // turn NAT on
- {
- mblk_t* mp2;
- proxy_name_t* proxyParam;
- // UInt8 i;
-
- result = false;
- // get Continued message block with IOCTL data
- // is there any data?
- if (iocp->ioc_count >= sizeof(proxy_name_t)) {
- mp2 = mp->b_cont;
- proxyParam = (proxy_name_t*)mp2->b_rptr;
- // look for corresponding NAT table
- // for (i=0; i<kNatNumDim; i++) {
- // if (proxyParam->portNameHash == GetPortName(gNatTable[i])) {
- // // enable NAT for this table
- // SetNatOn(gNatTable[i], true);
- // result = true;
- // break;
- // }
- // }
- }
- }
- // respond with M_IOCACK
- mp->b_datap->db_type = M_IOCACK; // set message type
- iocp->ioc_error = 0;
- iocp->ioc_count = 0;
- iocp->ioc_rval = kProxyNoError;
- if (!result) iocp->ioc_rval = kProxyTableError;
- qreply(q, mp);
- return 0;
- case I_NatOff:
- // IOCTL to turn NAT off
- {
- mblk_t* mp2;
- proxy_name_t* proxyParam;
- // UInt8 i;
-
- result = false;
- // get Continued message block with IOCTL data
- // is there any data?
- if (iocp->ioc_count >= sizeof(proxy_name_t)) {
- mp2 = mp->b_cont;
- proxyParam = (proxy_name_t*)mp2->b_rptr;
- // look for corresponding NAT table
- /*
- for (i=0; i<kNatNumDim; i++) {
- if (proxyParam->portNameHash == GetPortName(gNatTable[i])) {
- // disable NAT for this table
- // SetNatOn(gNatTable[i], false);
- // set port name to indicate table is available
- // SetPortName(gNatTable[i], 0);
- // Init the NAT table to get ready for next time
- //InitTable(gNatTable[i], (UInt32)sizeof(gNatTable[i]));
- result = true;
- break;
- }
- }
- */
- }
- }
- // respond with M_IOCACK
- mp->b_datap->db_type = M_IOCACK; // set message type
- iocp->ioc_error = 0;
- iocp->ioc_count = 0;
- iocp->ioc_rval = kProxyNoError;
- if (!result) iocp->ioc_rval = kProxyTableError;
- qreply(q, mp);
- return 0;
- case I_LocalNatOn:
- // IOCTL to turn Local NAT on
- if (!gIsLocalNatOn) {
- gIsLocalNatOn = true;
- }
- // respond with M_IOCACK
- mp->b_datap->db_type = M_IOCACK; // set message type
- iocp->ioc_error = 0;
- iocp->ioc_count = 0;
- iocp->ioc_rval = kProxyNoError;
- qreply(q, mp);
- return 0;
- case I_LocalNatOff:
- // IOCTL to turn Local NAT off
- if (gIsLocalNatOn) {
- gIsLocalNatOn = false;
- }
- // respond with M_IOCACK
- mp->b_datap->db_type = M_IOCACK; // set message type
- iocp->ioc_error = 0;
- iocp->ioc_count = 0;
- iocp->ioc_rval = kProxyNoError;
- qreply(q, mp);
- return 0;
- case I_TRCableModem:
- // IOCTL to enable TRCableModem
- if (!gIsTRCableModem) {
- gIsTRCableModem = true;
- }
- // respond with M_IOCACK
- mp->b_datap->db_type = M_IOCACK; // set message type
- iocp->ioc_error = 0;
- iocp->ioc_count = 0;
- iocp->ioc_rval = kProxyNoError;
- qreply(q, mp);
- return 0;
- case I_TRCableModemOff:
- // IOCTL to disable TRCableModem
- if (gIsTRCableModem) {
- gIsTRCableModem = false;
- }
- // respond with M_IOCACK
- mp->b_datap->db_type = M_IOCACK; // set message type
- iocp->ioc_error = 0;
- iocp->ioc_count = 0;
- iocp->ioc_rval = kProxyNoError;
- qreply(q, mp);
- return 0;
- case I_DNSForwardingOn:
- // IOCTL to enable DNSForarding
- if (!gIsDNSForwarding) {
- gIsDNSForwarding = true;
- }
- // respond with M_IOCACK
- mp->b_datap->db_type = M_IOCACK; // set message type
- iocp->ioc_error = 0;
- iocp->ioc_count = 0;
- iocp->ioc_rval = kProxyNoError;
- qreply(q, mp);
- return 0;
- case I_DNSForwardingOff:
- // IOCTL to disable DNSForarding
- if (gIsDNSForwarding) {
- gIsDNSForwarding = false;
- }
- // respond with M_IOCACK
- mp->b_datap->db_type = M_IOCACK; // set message type
- iocp->ioc_error = 0;
- iocp->ioc_count = 0;
- iocp->ioc_rval = kProxyNoError;
- qreply(q, mp);
- return 0;
- case I_ClampMSS:
- // IOCTL to set TCP MSS clamp for proxy interface
- {
- mblk_t* mp2;
- proxy_mss_t* proxyParam;
- // UInt8 i;
-
- // get Continued message block with IOCTL data
- // is there any data?
- if (iocp->ioc_count >= sizeof(proxy_mss_t)) {
- mp2 = mp->b_cont;
- proxyParam = (proxy_mss_t*)mp2->b_rptr;
- // look for corresponding NAT table
- /*
- for (i=0; i<kNatNumDim; i++) {
- if (proxyParam->portNameHash == GetPortName(gNatTable[i])) {
- // set MSS Clamp for this table
- // SetMSSClamp(gNatTable[i], (UInt16)proxyParam->mssClamp);
- break;
- }
- }
- */
- }
- }
- // respond with M_IOCACK
- mp->b_datap->db_type = M_IOCACK; // set message type
- iocp->ioc_error = 0;
- //iocp->ioc_count = 0; // leave as sent
- iocp->ioc_rval = kProxyNoError;
- qreply(q, mp);
- return 0;
- case I_AgeNatTable:
- {
- mblk_t* mp2;
- proxy_age_t* proxyParam;
- UInt16 timeOut;
- // UInt16 count;
- // UInt8 i;
-
- timeOut = kTimeOutTCP; // initialize default
- // get Continued message block with IOCTL data
- // is there any data?
- if (iocp->ioc_count >= sizeof(proxy_age_t)) {
- mp2 = mp->b_cont;
- proxyParam = (proxy_age_t*)mp2->b_rptr;
- // Age table with timeout parameter
- timeOut = proxyParam->age;
- /*
- // look for corresponding NAT table
- for (i=0; i<kNatNumDim; i++) {
- if (proxyParam->portNameHash == GetPortName(gNatTable[i])) {
- // enable NAT for this table
- // count = AgeTable(gNatTable[i], timeOut);
- // return resulting number of entries
- proxyParam->age = count;
- result = true;
- break;
- }
- }
- */
- }
- }
- // respond with M_IOCACK
- mp->b_datap->db_type = M_IOCACK; // set message type
- iocp->ioc_error = 0;
- //iocp->ioc_count = 0; // leave as sent
- iocp->ioc_rval = kProxyNoError;
- qreply(q, mp);
- return 0;
-
- case I_SetOnDemandName:
- // IOCTL to set OnDemand Interface Name
- {
- mblk_t* mp2;
- proxy_name_t* proxyParam;
-
- // get Continued message block with IOCTL data
- // is there any data?
- if (iocp->ioc_count >= sizeof(proxy_name_t)) {
- mp2 = mp->b_cont;
- proxyParam = (proxy_name_t*)mp2->b_rptr;
- // save hashed interface name
- gOnDemandName = proxyParam->portNameHash;
- //OTKernelPrintf( kOTPrintThenStop, "IOCTL Set on demand name, param: %x \n", gInterfaceName);
- }
- }
- // respond with M_IOCACK
- mp->b_datap->db_type = M_IOCACK; // set message type
- iocp->ioc_error = 0;
- iocp->ioc_count = 0;
- iocp->ioc_rval = kProxyNoError;
- qreply(q, mp);
- return 0;
-
- case I_OnDemandUp:
- // IOCTL to indicate OnDemand is up
- gIsOnDemandUp = true;
- gIsOnDemandPending = false; // reset connection needed
- // respond with M_IOCACK
- mp->b_datap->db_type = M_IOCACK; // set message type
- iocp->ioc_error = 0;
- iocp->ioc_count = 0;
- iocp->ioc_rval = kProxyNoError;
- qreply(q, mp);
- return 0;
-
- case I_OnDemandDown:
- // IOCTL to indicate OnDemand is down
- gIsOnDemandPending = false; // reset connection needed
- gIsOnDemandUp = false;
- // respond with M_IOCACK
- mp->b_datap->db_type = M_IOCACK; // set message type
- iocp->ioc_error = 0;
- iocp->ioc_count = 0;
- iocp->ioc_rval = kProxyNoError;
- qreply(q, mp);
- return 0;
-
- case I_OnDemandConnect:
- // IOCTL to test if On Demand connection needed
- {
- mblk_t* mp2;
- NetNumber_t* addressParam;
-
- // get Continued message block with IOCTL data
- // is there any data?
- if (iocp->ioc_count >= sizeof(proxy_network_t)) {
- mp2 = mp->b_cont;
- addressParam = (NetNumber_t*)mp2->b_rptr;
- // return srcAddress of on demand traffic
- addressParam->address = gOnDemandSrcAddress;
- addressParam->mask = 0;
- }
- }
- // respond with M_IOCACK
- mp->b_datap->db_type = M_IOCACK; // set message type
- iocp->ioc_error = 0;
- //iocp->ioc_count = 0; // leave as sent
- iocp->ioc_rval = kProxyNoError;
- if (gIsOnDemandPending && (gIsOnDemandUp == false)) {
- iocp->ioc_rval = kProxyOnDemand;
- }
- qreply(q, mp);
- return 0;
-
- // Access to NAT Table
- case I_GetFullMap:
- index = 0; // default to first table
- {
- mblk_t* mp2;
- proxy_name_t* proxyParam;
- // UInt8 i;
-
- // get Continued message block with IOCTL data
- // is there any data?
- if (iocp->ioc_count >= sizeof(proxy_name_t)) {
- mp2 = mp->b_cont;
- proxyParam = (proxy_name_t*)mp2->b_rptr;
- // look for corresponding NAT table
- /*
- for (i=0; i<kNatNumDim; i++) {
- if (proxyParam->portNameHash == GetPortName(gNatTable[i])) {
- // remember which NAT table
- index = i;
- break;
- }
- }
- */
- }
- }
- // respond with M_IOCACK
- mp->b_datap->db_type = M_IOCACK; // set message type
- iocp->ioc_error = 0;
- iocp->ioc_count = 0;
- iocp->ioc_rval = kProxyNoError;
- qreply(q, mp);
- // send requested data
- // result = proxy_SendNat(gNatTable[index], RD(q), kFullMap);
- return 0;
- case I_GetStaticMap:
- index = 0; // default to first table
- {
- mblk_t* mp2;
- proxy_name_t* proxyParam;
- // UInt8 i;
-
- // get Continued message block with IOCTL data
- // is there any data?
- if (iocp->ioc_count >= sizeof(proxy_name_t)) {
- mp2 = mp->b_cont;
- proxyParam = (proxy_name_t*)mp2->b_rptr;
-
- // look for corresponding NAT table
- /* for (i=0; i<kNatNumDim; i++) {
- if (proxyParam->portNameHash == GetPortName(gNatTable[i])) {
- // remember which NAT table
- index = i;
- break;
- }
- }
- */
- }
- }
- // respond with M_IOCACK
- mp->b_datap->db_type = M_IOCACK; // set message type
- iocp->ioc_error = 0;
- iocp->ioc_count = 0;
- iocp->ioc_rval = kProxyNoError;
- qreply(q, mp);
- // send requested data
- // result = proxy_SendNat(gNatTable[index], RD(q), kStaticMap);
- return 0;
- case I_AddMapEntry:
- {
- mblk_t* mp2;
- proxy_map_entry_t* proxyParam;
- translationEntry_t tableEntry;
- // UInt8 i;
- index = 0; // default to first table
- // get Continued message block with IOCTL data
- // is there any data?
- if (iocp->ioc_count >= sizeof(proxy_map_entry_t)) {
- mp2 = mp->b_cont;
- proxyParam = (proxy_map_entry_t*)mp2->b_rptr;
- // look for corresponding NAT table
- /*
- for (i=0; i<kNatNumDim; i++) {
- if (proxyParam->portNameHash == GetPortName(gNatTable[i])) {
- // remember which NAT table
- index = i;
- break;
- }
- }
- */
- }
- // load search info
- bzero(&tableEntry, sizeof(translationEntry_t));
- tableEntry.apparent = proxyParam->mapEntry.apparent;
- tableEntry.portRange= proxyParam->mapEntry.portRange;
- tableEntry.actual = proxyParam->mapEntry.actual;
- tableEntry.protocol = proxyParam->mapEntry.protocol;
- tableEntry.age = proxyParam->mapEntry.age;
- tableEntry.flags = proxyParam->mapEntry.flags;
- // find table entry if any
- // tableEntry.entryID = FindEntry(gNatTable[index], &tableEntry);
- // add to table
- // result = WriteEntry(gNatTable[index], &tableEntry);
- }
- // respond with M_IOCACK
- mp->b_datap->db_type = M_IOCACK; // set message type
- iocp->ioc_error = 0;
- iocp->ioc_count = 0;
- iocp->ioc_rval = kProxyNoError;
- if (!result) iocp->ioc_rval = kProxyAddError;
- qreply(q, mp);
- return 0;
- case I_DelMapEntry:
- {
- mblk_t* mp2;
- proxy_map_entry_t* proxyParam;
- translationEntry_t tableEntry;
- UInt16 entryID;
- UInt16 prev;
- // UInt8 i;
- index = 0; // default to first table
- result = false;
- // get Continued message block with IOCTL data
- // is there any data?
- if (iocp->ioc_count >= sizeof(proxy_map_entry_t)) {
- mp2 = mp->b_cont;
- proxyParam = (proxy_map_entry_t*)mp2->b_rptr;
- /*
- // look for corresponding NAT table
- for (i=0; i<kNatNumDim; i++) {
- if (proxyParam->portNameHash == GetPortName(gNatTable[i])) {
- // remember which NAT table
- index = i;
- break;
- }
- }
- */
- }
- // load search info
- tableEntry.apparent = proxyParam->mapEntry.apparent;
- tableEntry.portRange= proxyParam->mapEntry.portRange;
- tableEntry.actual = proxyParam->mapEntry.actual;
- tableEntry.protocol = proxyParam->mapEntry.protocol;
- tableEntry.age = proxyParam->mapEntry.age;
- tableEntry.flags = proxyParam->mapEntry.flags;
- // find table entry if any
- // entryID = FindEntry(gNatTable[index], &tableEntry);
- // try to delete it
- prev = 0;
- if (entryID != 0) {
- // DeleteEntry(gNatTable[index], entryID, prev);
- result = true;
- } else result = false;
- }
- // respond with M_IOCACK
- mp->b_datap->db_type = M_IOCACK; // set message type
- iocp->ioc_error = 0;
- iocp->ioc_count = 0;
- iocp->ioc_rval = kProxyNoError;
- if (!result) iocp->ioc_rval = kProxyDelError;
- qreply(q, mp);
- return 0;
-
- // Access to filter table
- case I_GetFilters:
- // respond with M_IOCACK
- mp->b_datap->db_type = M_IOCACK; // set message type
- iocp->ioc_error = 0;
- iocp->ioc_count = 0;
- iocp->ioc_rval = kProxyNoError;
- qreply(q, mp);
- // send requested data
- // proxy_SendFilters(RD(q));
- return 0;
- case I_AddFilterEntry:
- {
- mblk_t* mp2;
- FilterEntry_t* filterEntry;
- // get Continued message block with IOCTL data
- // is there any data?
- if (iocp->ioc_count >= sizeof(FilterEntry_t)) {
- mp2 = mp->b_cont;
- filterEntry = (FilterEntry_t*)mp2->b_rptr;
- // add to table
- // result = WriteFilterEntry(gFilterTable, filterEntry);
- }
- }
- // respond with M_IOCACK
- mp->b_datap->db_type = M_IOCACK; // set message type
- iocp->ioc_error = 0;
- iocp->ioc_count = 0;
- iocp->ioc_rval = kProxyNoError;
- if (!result) iocp->ioc_rval = kProxyAddError;
- qreply(q, mp);
- return 0;
- case I_DelFilterEntry:
- {
- mblk_t* mp2;
- FilterEntry_t* filterEntry;
- UInt16 index;
- UInt16 prev;
- // get Continued message block with IOCTL data
- // is there any data?
- if (iocp->ioc_count >= sizeof(FilterEntry_t)) {
- mp2 = mp->b_cont;
- filterEntry = (FilterEntry_t*)mp2->b_rptr;
- // find table entry if any
- // index = FindFilterEntry(gFilterTable, filterEntry);
- // try to delete it
- prev = 0;
- if (index != 0) {
- // DeleteFilterEntry(gFilterTable, index, prev);
- result = true;
- } else result = false;
- }
- }
- // respond with M_IOCACK
- mp->b_datap->db_type = M_IOCACK; // set message type
- iocp->ioc_error = 0;
- iocp->ioc_count = 0;
- iocp->ioc_rval = kProxyNoError;
- if (!result) iocp->ioc_rval = kProxyDelError;
- qreply(q, mp);
- return 0;
-
- default:
- // As a driver, it is our responsibility to NAK any IOCTL we receive
- // that we don't understand. If we were a module, we would just pass it on.
- iocp->ioc_error = EINVAL;
- iocp->ioc_count = 0;
- mp->b_datap->db_type = M_IOCNAK;
- qreply(q, mp);
- return 0;
- }
- }
- break;
-
- /*
- * Handle data coming from the client
- */
- case M_DATA:
- return proxy_wdata(q, mp);
-
- /*
- * Handle M_PROTO and M_PCPROTO requests coming from the client
- */
- case M_PROTO:
- case M_PCPROTO:
- return proxy_wproto(q, mp);
-
- /*
- * Should never see one of these messages. It is an invisible message
- * used by the streamhead.
- */
- case M_PASSFP:
- break;
-
- default:
- break;
- }
- // There's no one to pass it on to, so just free the message.
- // OTKernelPrintf( kOTPrintThenStop, "proxy_wput, unexpected db_type: %d.\n", mp->b_datap->db_type);
- freemsg(mp);
- return 0;
- }
-
- /*******************************************************************************
- ** Read-side put routine
- ********************************************************************************/
-
- int proxy_rput(queue_t* q, mblk_t* mp)
- {
- //OTKernelPrintf( kOTPrintThenStop, "Entering proxy_rput, db_type: %d.\n", mp->b_datap->db_type);
- proxy_struct* myData = (proxy_struct*)q->q_ptr;
- /*
- * Process the incoming message from a timer or any other
- * We're a driver, so there's no one below us.
- */
- switch (mp->b_datap->db_type)
- {
- /*
- * Miscellaneous messages - pass them on if you don't want them
- */
- case M_STOP:
- case M_START:
- case M_STOPI:
- case M_STARTI:
- break;
-
- /*
- * Just send these on up to the streamhead
- */
- case M_COPYIN:
- case M_COPYOUT:
- case M_ERROR:
- case M_HANGUP:
- case M_PCRSE:
- break;
-
- /*
- * If we send any IOCTLs downstream, look at the acks and
- * nacks here to determine if these are ours. If so, process
- * them. Otherwise, just send them on upstream
- */
- case M_IOCACK:
- case M_IOCNAK:
- break;
-
- /*
- * If we ure any timers, process them here. Otherwise, send
- * the signal upstream
- */
- case M_PCSIG:
- // record timer has been delivered, so we don't try to cancel it
- myData->timerMessage = nilp(mblk_t);
- // Test if message is valid
- if ( !mi_timer_valid(mp) ) return 0; // If not valid, ignore it!
- mi_timer_free(mp); // free the message
- // Send timed stat message upstream if monitoring is turned on
- if ( myData->monitorIsOnFlag ) {
- proxy_SendStats(q);
- /*
- // Check if companion stream module is still configured
- if (proxymInstallInfo.ref_count == 0) {
- // companion module is no longer configured, nothing to monitor
- // turn off monitoring
- myData->monitorIsOnFlag = false;
- return 0;
- }
- */
- // try to allocate new timer message (q, size)
- myData->timerMessage = mi_timer_alloc(q, kTimerSize);
- // schedule message
- if (myData->timerMessage) mi_timer(myData->timerMessage, kTimerDelay);
- else {
- myData->monitorIsOnFlag = false; // alloc failed, so monitoring is off
- myData->timerSequenceNumber = 0; // reset sequence numbers
- }
- }
- return 0;
-
- /*
- * Undocumented message type - send it on
- */
- case M_HPDATA:
- break;
-
-
- /*
- * Handle data coming from downstream
- */
- //case M_DATA:
- // return proxy_rdata(q, mp);
-
- /*
- * Handle M_PROTO and M_PCPROTO requests coming from downstream
- */
- //case M_PROTO:
- //case M_PCPROTO:
- // return proxy_rproto(q, mp);
-
- /*
- * Anything we don't understand - just pass it on
- */
- default:
- break;
- }
- // OTKernelPrintf( kOTPrintThenStop, "proxy_rput, unexpected db_type: %d.\n", mp->b_datap->db_type);
- putnext(q, mp);
- return 0;
- }
-
- #pragma mark • module support functions •
-
-
- /*******************************************************************************
- ** Write-side processing routines
- ********************************************************************************/
-
- int proxy_wdata(queue_t* q, mblk_t* mp)
- {
- /* ---------------------------------------------------------------------
- Here, we do whatever munging we're going to do on the client data,
- then send it on.
- Keep in mind that we call this routine from the proxy_wproto routine,
- so that the first block of the message might be an M_PROTO, and not
- data.
- --------------------------------------------------------------------- */
-
- /*
- * Since we're a driver, there's no one to send it on to.
- * Just free the message.
- */
- // OTKernelPrintf( kOTPrintThenStop, "proxy_data entered unexpectedly.\n");
- freemsg(mp);
- return ENXIO;
- }
-
- int proxy_wproto(queue_t* q, mblk_t* mp)
- {
- proxy_struct* myData = (proxy_struct*)q->q_ptr;
- //struct module_info* nextinfo;
- /*
- * If the message block is not big enough - blow it away
- */
- if ( mp->b_wptr - mp->b_rptr < sizeof(long) )
- {
- freemsg(mp);
- return 0;
- }
- /*
- * Look at the incoming primitive message
- */
- //if ( ((union T_primitives*)mp->b_rptr)->type != T_INFO_REQ) {
- // OTKernelPrintf( kOTPrintOnly, "Entering proxy_wproto, prim_type: %d.\n",
- // ((union T_primitives*)mp->b_rptr)->type);
- //}
-
- switch ( ((union T_primitives*)mp->b_rptr)->type )
- {
- /*
- * For incoming data, let proxy_wdata handle it
- */
- case T_UNITDATA_REQ:
- return proxy_wdata(q, mp);
-
- case T_INFO_REQ:
- //OTKernelPrintf( kOTPrintThenStop, "T_INFO_REQ \n");
- // respond with T_INFO_ACK
- mp = ReuseMessage(mp, sizeof(T_info_ack) ); // get a message block
- if (mp == nilp(mblk_t)) return ENOBUFS;
- mp->b_datap->db_type = M_PCPROTO; // set message type
- ((T_info_ack*)mp->b_wptr)->PRIM_type = T_INFO_ACK;
- ((T_info_ack*)mp->b_wptr)->TSDU_size = 255;
- ((T_info_ack*)mp->b_wptr)->ETSDU_size = -2; // -2 for connectionless service
- ((T_info_ack*)mp->b_wptr)->CDATA_size = -2;
- ((T_info_ack*)mp->b_wptr)->DDATA_size = -2;
- ((T_info_ack*)mp->b_wptr)->ADDR_size = sizeof(InetAddress);
- ((T_info_ack*)mp->b_wptr)->OPT_size = -3; // no options
- ((T_info_ack*)mp->b_wptr)->TIDU_size = 255;
- ((T_info_ack*)mp->b_wptr)->SERV_type = T_CLTS;
- ((T_info_ack*)mp->b_wptr)->CURRENT_state= myData->myState;
- ((T_info_ack*)mp->b_wptr)->PROVIDER_flag= SENDZERO;
- mp->b_wptr += sizeof(T_info_ack);
- qreply(q, mp);
- return 0;
-
- case T_OPTMGMT_REQ:
- //OTKernelPrintf( kOTPrintOnly, "T_OPTMGMT_REQ \n");
- // respond with T_OPTMGMT_ACK
- mp = ReuseMessage(mp, sizeof(T_optmgmt_ack) ); // get a message block
- if (mp == nilp(mblk_t)) return ENOBUFS;
- mp->b_datap->db_type = M_PCPROTO; // set message type
- ((T_optmgmt_ack*)mp->b_wptr)->PRIM_type = T_OPTMGMT_ACK;
- // others same as received
- mp->b_wptr += sizeof(T_optmgmt_ack);
- qreply(q, mp);
- return 0;
-
- case T_BIND_REQ:
- // respond with T_BIND_ACK
- // re-use message block
- mp->b_datap->db_type = M_PCPROTO; // set message type
- ((T_bind_ack*)mp->b_rptr)->PRIM_type = T_BIND_ACK;
- myData->myState = TS_IDLE;
- qreply(q, mp);
- return 0;
-
- case T_UNBIND_REQ:
- // respond with T_OK_ACK
- mp = ReuseMessage(mp, sizeof(T_ok_ack) ); // get a message block
- if (mp == nilp(mblk_t)) return ENOBUFS;
- mp->b_datap->db_type = M_PCPROTO; // set message type
- ((T_ok_ack*)mp->b_wptr)->PRIM_type = T_OK_ACK;
- ((T_ok_ack*)mp->b_wptr)->CORRECT_prim = T_UNBIND_REQ;
- mp->b_wptr += sizeof(T_ok_ack);
- myData->myState = TS_UNBND;
- qreply(q, mp);
- return 0;
-
- default:
- break;
- }
- /*
- * Since we're a driver, there's no one to pass it on to.
- * Just free the message
- */
- // OTKernelPrintf( kOTPrintThenStop, "proxy_wproto, Unknown prim_type: %d.\n",
- // ((union T_primitives*)mp->b_rptr)->type);
- freemsg(mp);
- return ENXIO;
- }
-
- int proxy_wsrv(queue_t* q)
- {
- mblk_t* mp;
- /*
- * Send on downstream anything that was scheduled for flow control!
- * Since we're a driver, nothing should be scheduled
- */
- // OTKernelPrintf( kOTPrintThenStop, "proxy_wsrv, Unexpected data.\n");
-
- while ( (mp = getq(q)) != nilp(mblk_t) )
- {
- /*
- * If we're flow controlled, get out and we'll come back when the flow-
- * control lifts.
- */
- if ( !bcanput(q->q_next, mp->b_band) )
- {
- putbq(q, mp);
- return 0;
- }
- /*
- * Otherwise, send the data downstream, and get some more
- */
- //OTKernelPrintf( kOTPrintThenStop, "wsrv, putnext \n");
- putnext(q, mp);
- }
- return 0;
- }
-
- /*******************************************************************************
- ** Read-side process routines
- ********************************************************************************/
-
- int proxy_rdata(queue_t* q, mblk_t* mp)
- {
- proxy_struct* myData = (proxy_struct*)q->q_ptr;
- /*
- * If we're not ready for incoming data, just free it up
- */
- if ( myData->myState != DL_IDLE )
- {
- freemsg(mp);
- return 0;
- }
-
- /* ---------------------------------------------------------------------
- Here, we do whatever munging we're going to do on the incoming data,
- then send it on.
- Keep in mind that we call this routine from the proxy_rproto routine,
- so that the first block of the message might be an M_PROTO, and not
- data.
- --------------------------------------------------------------------- */
-
- /*
- * Now, we send it on. If we can't because of flow control, use
- * putq to put it on our queue and send it on later.
- */
- if ( !bcanput(q->q_next, mp->b_band) )
- putq(q, mp);
- else
- putnext(q, mp);
- return 0;
- }
-
- int proxy_rproto(queue_t* q, mblk_t* mp)
- {
- Boolean doOutState = false;
- proxy_struct* myData = (proxy_struct*)q->q_ptr;
- /*
- * If the message block is not big enough - blow it away
- */
- if ( mp->b_wptr - mp->b_rptr < sizeof(long) )
- {
- freemsg(mp);
- return 0;
- }
- /*
- * Look at the incoming primitive message
- */
- switch ( ((union T_primitives*)mp->b_rptr)->type )
- {
- /*
- * For incoming data, let proxy_rdata handle it
- */
- case DL_UNITDATA_IND:
- return proxy_rdata(q, mp);
- /*
- * These are just passed on, since we don't deal with them
- */
- case DL_INFO_ACK:
- //case T_ADDR_ACK:
- //case T_RESOLVEADDR_ACK:
- //case T_OPTMGMT_ACK:
- break;
-
- /*
- * Here, a bind request succeeded.
- */
- case DL_BIND_ACK:
- myData->myState = DL_IDLE;
- break;
-
- /*
- * Handle any error acks that come back
- */
- case DL_ERROR_ACK:
- {
- switch ( ((dl_error_ack_t*)mp->b_rptr)->dl_error_primitive )
- {
- /*
- * These are error acks for functions we just pass thru
- */
- case DL_INFO_REQ:
- //case T_ADDR_REQ:
- //case T_OPTMGMT_REQ:
- break;
-
- /*
- * If the unbind failed, then we are not unbound either.
- * Send the error on up to the client.
- */
- case DL_UNBIND_REQ:
- myData->myState = DL_IDLE;
- break;
-
- /*
- * If the bind failed, we fall back to the unbound state
- */
- case DL_BIND_REQ:
- myData->myState = DL_UNBOUND;
- break;
-
- //case T_CONN_REQ:
- //case T_CONN_RES:
- //case T_DISCON_REQ:
- /*
- * %%% Needs implementation
- */
- //break;
-
- /*
- * Any error acks we don't understand just pass on
- */
- default:
- break;
- }
- break;
- }
-
- /*
- * Handle any OK acks that come back
- */
- case DL_OK_ACK:
- {
- switch ( ((dl_ok_ack_t*)mp->b_rptr)->dl_correct_primitive )
- {
- /*
- * If the unbind is OK, we are no longer unbound.
- */
- case DL_UNBIND_REQ:
- myData->myState = DL_UNBOUND;
- break;
-
- case DL_BIND_REQ:
- myData->myState = DL_IDLE;
- break;
-
- //case T_CONN_REQ:
- //case T_CONN_RES:
- //case T_DISCON_REQ:
- /*
- * %%% Needs implementation - Kill any that have their
- * own acking mechanism.
- */
- // break;
-
- /*
- * Any error acks we don't understand just pass on
- */
- default:
- break;
- }
- break;
- }
-
- //case T_CONN_IND:
- //case T_CONN_CON:
- //case T_DISCON_IND:
- //case T_ORDREL_IND:
- /*
- * %%% Needs implementation
- */
- // break;
-
- /*
- * Anything else we don't understand, just send it on
- */
- default:
- break;
- } /*
- * Here, we just pass the message block on to the next layer, or
- * queue it up till flow control is lifted.
- */
- if (mp->b_datap->db_type > QPCTL || canput(q->q_next) )
- putnext(q, mp);
- else
- putq(q, mp);
- return 0;
- }
-
- int proxy_rsrv(queue_t* q)
- {
- mblk_t* mp;
- /*
- * Send on up anything that was scheduled for flow control!
- */
- while ( (mp = getq(q)) != nilp(mblk_t) )
- {
- /*
- * If we're flow controlled, get out and we'll come back when the flow-
- * control lifts.
- */
- if ( !bcanput(q->q_next, mp->b_band) )
- {
- putbq(q, mp);
- return 0;
- }
- /*
- * Otherwise, send the data upstream, and get some more
- */
- putnext(q, mp);
- }
- return 0;
- }
-
- #pragma mark • generic support functions •
-
- // ---------------------------------------------------------------------------------
- // • proxy Get Timed Stat
- // ---------------------------------------------------------------------------------
- // Return timed stat data counters and reset
- void proxy_GetTimedStat(queue_t* q, SInt32* outSequenceNumber, SInt32* outRCount, SInt32* outWCount)
- {
- proxy_struct* myData = (proxy_struct*)q->q_ptr;
-
- SInt32 myRCount;
- SInt32 myWCount;
-
- // read the stat values
- myRCount = mstat.rCount;
- myWCount = mstat.wCount;
-
- // Reset the data counters carefully so we don't miss anything
- // (subtract only the number we read)
- OTAtomicAdd32(-myRCount, &mstat.rCount);
- OTAtomicAdd32(-myWCount, &mstat.wCount);
-
- // set return values (if pointers are not nil)
- if (outSequenceNumber) *outSequenceNumber = myData->timerSequenceNumber;
- if (outRCount) *outRCount = myRCount;
- if (outWCount) *outWCount = myWCount;
-
- myData->timerUnAckCount += 1; // Increment Unacked so we can stop if needed.
- myData->timerSequenceNumber += 1; // increment timer sequence number for reference
- }
-
-
- // ---------------------------------------------------------------------------------
- // • proxy Send Filters
- // ---------------------------------------------------------------------------------
- // Sends Filter table to client
- Boolean proxy_SendFilters(queue_t* q)
- {
- mblk_t* fmp; // filter message pointer
- mblk_t* udmp; // unit data message pointer
- InetAddress src;
- UInt32 opt;
- dl_filter_message_t* mb; // message buffer
- size_t size;
- //proxy_struct* myData = (proxy_struct*)q->q_ptr;
-
- FilterTableData_t* data; // Filter table access
- UInt16 index;
- UInt16 loopCount; // defensive prevent looping
- UInt8 count;
- Boolean result = false;
-
- // get Filter table threads
- data = (FilterTableData_t*)gFilterTable;
- // walk active entry list
- index = data->firstActive;
- loopCount = 0;
-
- do {
- // create an M_DATA message to send our Filter data
- size = sizeof(dl_filter_message_t);
- fmp = allocb(size, BPRI_LO);
- if (fmp == nilp(mblk_t)) { // if we didn't get a block
- break; // get out
- }
- // Standard defines type = M_DATA, b_rptr and b_wptr to b_datap->db_base,
- // b_band = 0, ref count = 1
-
- // set data in message buffer
- mb = (dl_filter_message_t*)fmp->b_wptr;
- mb->dl_primitive = DL_FILTER_MESSAGE;
- // transfer table data to buffer
- count = 0;
- while ((index > 0) && (count < kFilterMessageDim)) {
- mb->array[count].portName = gFilterTable[index].portName;
- mb->array[count].flags = gFilterTable[index].flags;
- mb->array[count].protocol = gFilterTable[index].protocol;
- mb->array[count].sourceNet.address = gFilterTable[index].sourceNet.address;
- mb->array[count].sourceNet.mask = gFilterTable[index].sourceNet.mask;
- mb->array[count].sourcePorts.lo = gFilterTable[index].sourcePorts.lo;
- mb->array[count].sourcePorts.hi = gFilterTable[index].sourcePorts.hi;
- mb->array[count].destNet.address = gFilterTable[index].destNet.address;
- mb->array[count].destNet.mask = gFilterTable[index].destNet.mask;
- mb->array[count].destPorts.lo = gFilterTable[index].destPorts.lo;
- mb->array[count].destPorts.hi = gFilterTable[index].destPorts.hi;
- mb->array[count].entryID = index;
- count += 1;
-
- index = gFilterTable[index].entryID;
- loopCount += 1; // defensive, test for bad link
- if ((index > data->lastUsed) || (loopCount > data->lastUsed)) break;
- }
- if (index) mb->dl_status = 1; // more entries?
- else mb->dl_status = 0;
- mb->dl_number = count; // number of entries included
-
- // initialize the message
- fmp->b_cont = nilp(mblk_t); // no trailer
- fmp->b_wptr = fmp->b_rptr + size;
-
- // Create a T_UNITDATA_IND message with our stat message block attached
- //OTInitInetAddress(&src, (InetPort)0, (InetHost)0);
- BZERO(&src, sizeof(InetAddress));
- src.fAddressType = AF_INET;
- src.fPort = 0;
- src.fHost = DL_FILTER_MESSAGE;
- opt = 0;
- udmp = my_tpi_unitdata_ind(fmp, (char*)&src, sizeof(InetAddress), (char*)&opt, 0);
- if (udmp == nilp(mblk_t)) {
- freemsg(fmp); // release the M_DATA message
- break; // get out
- }
-
- // schedule ourselves to send T_UNITDATA_IND messages upstream.
- putq(q, udmp);
- result = true;
-
- // defensive, test for bad link
- if ((index > data->lastUsed) || (loopCount > data->lastUsed)) break;
-
- } while (index != 0);
-
- return result;
- }
-
-
- // ---------------------------------------------------------------------------------
- // • proxy Send Nat
- // ---------------------------------------------------------------------------------
- // Sends NAT table to client
- Boolean proxy_SendNat(translationEntry_t table[], queue_t* q, UInt8 selector)
- {
- mblk_t* nmp; // NAT message pointer
- mblk_t* udmp; // unit data message pointer
- InetAddress src;
- UInt32 opt;
- dl_port_map_t* mb; // message buffer
- size_t size;
- //proxy_struct* myData = (proxy_struct*)q->q_ptr;
-
- tableData_t* data; // NAT table access
- UInt16 index;
- UInt16 loopCount; // defensive prevent looping
- UInt8 count;
- Boolean result = false;
-
- // get NAT table threads
- data = (tableData_t*)table;
- // walk active entry list
- index = data->firstActive;
- loopCount = 0;
-
- do {
- // create an M_DATA message to send our NAT data
- size = sizeof(dl_port_map_t);
- nmp = allocb(size, BPRI_LO);
- if (nmp == nilp(mblk_t)) { // if we didn't get a block
- break; // get out
- }
- // Standard defines type = M_DATA, b_rptr and b_wptr to b_datap->db_base,
- // b_band = 0, ref count = 1
-
- // set data in message buffer
- mb = (dl_port_map_t*)nmp->b_wptr;
- mb->dl_primitive = DL_PORT_MAP;
- // transfer table data to buffer
- count = 0;
- while ((index > 0) && (count < kPortMapEntryDim)) {
- if ((selector == kFullMap) ||
- ((selector == kStaticMap) && (table[index].flags & kFlagPermanent))) {
- mb->array[count].apparent = table[index].apparent;
- mb->array[count].portRange = table[index].portRange;
- mb->array[count].actual = table[index].actual;
- mb->array[count].age = table[index].age;
- mb->array[count].flags = table[index].flags;
- mb->array[count].protocol = table[index].protocol;
- count += 1;
- }
- index = table[index].entryID;
- loopCount += 1; // defensive, test for bad link
- if ((index > data->lastUsed) || (loopCount > data->lastUsed)) break;
- }
- if (index) mb->dl_status = 1; // more entries?
- else mb->dl_status = 0;
- mb->dl_number = count; // number of entries included
-
- // initialize the message
- nmp->b_cont = nilp(mblk_t); // no trailer
- nmp->b_wptr = nmp->b_rptr + size;
-
- // Create a T_UNITDATA_IND message with our stat message block attached
- //OTInitInetAddress(&src, (InetPort)0, (InetHost)0);
- BZERO(&src, sizeof(InetAddress));
- src.fAddressType = AF_INET;
- src.fPort = 0;
- src.fHost = DL_PORT_MAP;
- opt = 0;
- udmp = my_tpi_unitdata_ind(nmp, (char*)&src, sizeof(InetAddress), (char*)&opt, 0);
- if (udmp == nilp(mblk_t)) {
- freemsg(nmp); // release the M_DATA message
- break; // get out
- }
-
- // schedule ourselves to send T_UNITDATA_IND messages upstream.
- putq(q, udmp);
- result = true;
-
- // defensive, test for bad link
- if ((index > data->lastUsed) || (loopCount > data->lastUsed)) break;
-
- } while (index != 0);
-
- return result;
- }
-
-
- // ---------------------------------------------------------------------------------
- // • proxy Send Stats
- // ---------------------------------------------------------------------------------
- // Send stats to client - returns true if stats were sent
- Boolean proxy_SendStats(queue_t* q)
- {
- mblk_t* smp; // stat message pointer
- mblk_t* udmp; // unit data message pointer
- InetAddress src;
- UInt32 opt;
- dl_timed_stat_t* sb; // stat buffer
- size_t size;
- proxy_struct* myData = (proxy_struct*)q->q_ptr;
-
- // If client isn't updating, stop sending
- if (myData->timerUnAckCount > 31) { // limit 30 unacked
- proxy_GetTimedStat(q, nil, nil, nil); // re-initialize stat counters
- return false;
- }
-
- // create an M_DATA message to send our timed stat data
- size = sizeof(dl_timed_stat_t);
- smp = allocb(size, BPRI_LO);
- if (smp == nilp(mblk_t)) { // if we didn't get a block
- return false; // get out
- }
- // Standard defines type = M_DATA, b_rptr and b_wptr to b_datap->db_base,
- // b_band = 0, ref count = 1
-
- // set data in message buffer
- sb = (dl_timed_stat_t*)smp->b_wptr;
- sb->dl_primitive = DL_TIMED_STAT;
- proxy_GetTimedStat(q, &sb->dl_sequence, &sb->dl_rCount, &sb->dl_wCount);
-
- // initialize the message
- smp->b_cont = nilp(mblk_t); // no trailer
- smp->b_wptr = smp->b_rptr + size;
-
- // Create a T_UNITDATA_IND message with our stat message block attached
- //OTInitInetAddress(&src, (InetPort)0, (InetHost)0);
- BZERO(&src, sizeof(InetAddress));
- src.fAddressType = AF_INET;
- src.fPort = 0;
- src.fHost = DL_TIMED_STAT;
- opt = 0;
- udmp = my_tpi_unitdata_ind(smp, (char*)&src, sizeof(InetAddress), (char*)&opt, 0);
- if (udmp == nilp(mblk_t)) {
- freemsg(smp); // release the M_DATA message
- return false; // get out
- }
-
- // send T_UNITDATA_IND message upstream.
- if ( !bcanput(q->q_next, udmp->b_band) ) {
- putq(q, udmp);
- } else {
- putnext(q, udmp);
- }
- return true;
- }
-
-
- // ---------------------------------------------------------------------------------
- // • mi_tpi_unitdata_ind
- // ---------------------------------------------------------------------------------
- // Allocate and initialize a unitdata indication message
- mblk_t* my_tpi_unitdata_ind(mblk_t* trailer_mp, char* src, size_t src_length,
- char* opt, size_t opt_length)
- {
- mblk_t* mp;
- size_t size;
- T_unitdata_ind* ud;
-
- // create a T_UNITDATA_IND message
- size = sizeof(T_unitdata_ind) + src_length + opt_length;
- mp = allocb(size, BPRI_LO);
- if (mp == nilp(mblk_t)) { // if we didn't get a block
- return nilp(mblk_t); // get out
- }
- // Standard defines type = M_DATA, b_rptr and b_wptr to b_datap->db_base,
- // b_band = 0, ref count = 1
-
- // initialize message in data buffer
- ud = (T_unitdata_ind*)mp->b_wptr;
- ud->PRIM_type = T_UNITDATA_IND;
- ud->SRC_length = src_length;
- ud->SRC_offset = sizeof(T_unitdata_ind);
- ud->OPT_length = opt_length;
- ud->OPT_offset = ud->SRC_offset + src_length;
- mp->b_wptr += sizeof(T_unitdata_ind);
- if (src_length > 0)
- bcopy(src, mp->b_wptr, src_length);
- mp->b_wptr += src_length;
- if (opt_length > 0)
- bcopy(opt, mp->b_wptr, opt_length );
- mp->b_wptr += opt_length;
-
- // initialize the message
- mp->b_cont = trailer_mp; // attach trailer mp
- mp->b_datap->db_type = M_PROTO; // set message type
-
- return mp;
- }
-
-
-
- #pragma mark • Macintosh Install Info •
-
- /* ------------------------------------------------------------------------
-
- THESE FUNCTIONS AND DATA STRUCTURES ARE SPECIFIC TO THE MACINTOSH IMPLEMENTATION
- OF STREAMS. THESE ROUTINES WOULD NOT EXIST IN OTHER STREAMS ENVIRONMENTS.
-
- WHEN PORTING OTHER STREAMS CODE TO THE MACINTOSH, THESE ROUTINES AND DATA
- STRUCTURES MUST BE ADDED.
-
- ------------------------------------------------------------------------ */
- install_info* GetOTProxyInstallInfo();
- Boolean InitProxyStreamModule(void* cookie);
-
- /*******************************************************************************
- ** install_info structure, and the GetInstallInfo function
- **
- ** This is the structure that tells Open Transport about your module. OT calls
- ** your "GetInstallInfo" function to get this information.
- **
- ********************************************************************************/
-
- install_info* GetOTProxyInstallInfo()
- {
- return &proxyInstallInfo;
- }
-
- /*******************************************************************************
- ** This is the function that will be called the first time that this code
- ** is loaded. It is guaranteed that this function is call at SystemTask time
- ** on the Macintosh.
- ********************************************************************************/
-
- Boolean InitProxyStreamModule(void* cookie)
- {
- // UInt8 i;
-
- /* Do any machine specific initialization stuff you need to */;
- gProxyListHead = NULL;
- proxyRefCountAdjusted = false;
- // Init the NAT table
- gNatTable[0] = gNatTable0;
- gNatTable[1] = gNatTable1;
- gNatTable[2] = gNatTable2;
- gNatTable[3] = gNatTable3;
- // for (i=0; i<kNatNumDim; i++) {
- // InitTable(gNatTable[i]);
- // }
- gIsLocalNatOn = false;
- gIsTRCableModem = false;
- gIsDNSForwarding = true; // DNS forwarding defaults to On
- gIsOnDemandUp = true;
- gIsOnDemandPending = false;
- gOnDemandName = HashName("IPCP"); // invoke IPCP driver On Demand
- gOnDemandSrcAddress = 0;
- gMonitorName = 0;
- // Init the Filter table
- // InitFilterTable(gFilterTable);
-
- // Init FlakeWay
- gFlakePercent = 0;
- gFlakeLatency = 0;
-
- return true;
- }
-